2025年12月: Rustで書かれた高速型チェッカーPyreflyの紹介(ryu22e)¶
筒井@ryu22eです。 今月の『Python Monthly Topics』は、型チェッカー「Pyrefly」を紹介します。
Pyreflyの概要と特徴¶
PyreflyはMeta社が開発した型チェッカーです。ロゴがホタル(firefly)をイメージしたデザインで、「パイアフライ」と発音します。[1]
Pythonの型チェッカーといえばMypy、Pyrightなどの既存ツールがありますが、 Pyreflyにはそれらにはない、以下の特徴があります。
Rustで実装されているため、高速に動作
WASM版もあるため、ブラウザ上で利用可能
コードに自動で型ヒントを付ける機能
Meta社製の型チェッカーといえばPyreがありますが、PyreflyはPyreの後継ツールです。 Pyreflyが誕生した経緯については、以下のMeta社のブログに詳細が書かれています。
Pythonの型システムが進化し、IDEから利用可能な型チェックの必要性が高まったため、新たなアプローチが必要となり、Pyreflyを開発したとのことです。
Pyreflyの使い方¶
それでは、Pyrefly使い方を紹介します。 以下のソースコードを型チェックの対象にします。
def convert_movie_info_into_md(title: str, year: int, description: str) -> str:
"""映画の情報をMarkdown形式で返す"""
markdown = f"# {title} ({year})\n\n{description}\n"
return markdown
print(
convert_movie_info_into_md(
"エピソード4/新たなる希望",
1977,
"銀河系を舞台にした壮大なスペースオペラの始まり。",
)
)
print(
convert_movie_info_into_md(
"エピソード5/帝国の逆襲",
1980,
"ダース・ベイダーが反乱軍を追い詰める。",
)
)
print(
convert_movie_info_into_md(
"エピソード6/ジェダイの帰還",
"1983", # 整数型にするべきところを文字列型にしている
"ルーク・スカイウォーカーがダース・ベイダーと対決する。",
)
)
PyreflyはCLIから使う方法と、IDEから使う方法があります。まずはCLIから使う方法を紹介します。 上記のexample.pyがカレントディレクトリにある状態で以下のコマンドを実行し、CLI版Pyreflyのインストールと初期化コマンドを実行します。
$ pip install pyrefly && pyrefly init
(省略)
INFO New config written to `/***/pyrefly.toml`
INFO Running pyrefly check...
INFO Checking project configured at `/***/pyrefly.toml`
INFO 1 error
Found 1 errors. We can add suppression comments (e.g., `pyrefly: ignore`) to silence them for you. Would you like to suppress them? (y/N):
コードにすでにエラーがある状態だと、「Found *** errors. We can add suppression comments...」というメッセージが出力されます。
これは、既存のエラーにignoreコメントを付けて、エラーを無視するようにするか確認しています。
「y」と入力してEnterキーを押すと、ソースコードのエラー箇所に# pyrefly: ignore [bad-argument-type]というコメントが付き、Pyreflyのチェック対象外になります(デフォルトは「N」)。
pyrefly initを実行すると、カレントディレクトリにpyrefly.tomlというファイルが出力されます。これが、Pyreflyの設定ファイルです。
また、pyproject.tomlがすでに存在する場合は、pyproject.tomlにPyreflyの設定が書き込まれます。
Pyreflyの設定項目については、以下の公式ドキュメントを参照してください。
https://pyrefly.org/en/docs/configuration/
型チェックを実行するコマンドはpyrefly checkです。実行すると、以下のようなエラーメッセージが出力されます。
pyrefly checkの実行結果¶$ pyrefly check
INFO Checking project configured at `/***/pyrefly.toml`
ERROR Argument `Literal['1983']` is not assignable to parameter `year` with type `int` in function `convert_movie_info_into_md` [bad-argument-type]
--> example.py:24:9
|
24 | "1983", # 整数型にするべきところを文字列型にしている
| ^^^^^^
|
INFO 1 error
次に、IDEまたはエディタから使う方法を紹介します。 PyreflyはVS Code、OpenVSX、PyCharm、Vim、Emacsなど、さまざまなIDE、エディタに対応しています。
Pyreflyが対応しているIDE、エディタについての詳細は、以下の公式ドキュメントを参照してください。
https://pyrefly.org/en/docs/IDE/
ここでは、VS Codeを使う例を紹介します。VS CodeのPyreflyエクステンションは以下からインストールできます。
https://marketplace.visualstudio.com/items?itemName=meta.pyrefly
上記をインストールした状態でexample.pyを開くと、VS Code上で以下のようにエラーメッセージが表示されます。
VS CodeのPyreflyエクステンションを導入した結果¶
Pyreflyと他の型チェッカーの速度を比較する¶
PyreflyはRustで実装されているため、他の型チェッカーより非常に高速です。 Sphinx 8.2.3のソースコードを対象に、Mypy、Pyright(Node.js版)、Pyreflyの3つのパフォーマンスを比較してみましょう。 結果は以下のとおりです。
ツール名 |
バージョン |
実行時間 |
|---|---|---|
Mypy |
1.19.0 |
4.19秒 |
Pyright |
1.1.407 |
16.81秒 |
Pyrefly |
0.43.1 |
2.17秒 |
Pyreflyの実行時間はMypyの約1/2、Pyrightの約1/8と、かなり高速であることが分かりました。
ちなみに、Pyreflyと同じくRustで実装されている型チェッカーとしてtyがあります。 tyは、Pythonのパッケージ管理ツールuvを開発しているAstral社製のツールです。 tyでも同様に実行時間を計測したところ、2.35秒という結果でした。 tyは本記事執筆時点ではアルファ版(バージョンは0.0.1-alpha.29)でまだ実用段階ではないため、単純に比較することはできませんが、Pyreflyと同程度の速度を期待できそうな数字です。
ブラウザからPyreflyを使ってみる¶
PyreflyはWASM版も提供されており、ブラウザ上から型チェックを利用できます。
以下の公式サイトでサンドボックスが使えます。
前述の「Pyreflyの使い方」で使ったサンプルコードも、以下のようにブラウザ上で型チェックしてエラーメッセージを表示させることができます。
サンドボックスの画面¶
コードに型ヒントをつけてくれるpyrefly inferコマンド¶
型チェッカーを導入したくても、現状のコードに型ヒントがないので活用できないというケースはよくあります。
Pyreflyには、型ヒントがないコードに型をつけるpyrefly inferという便利なコマンドがあります。
pyrefly inferについての公式ドキュメントは、以下を参照してください。
https://pyrefly.org/en/docs/autotype/
pyrefly inferコマンドの使い方を説明します。
まず、前述の「Pyreflyの使い方」で使用したコードから型ヒントをなくしたコードを用意します。
convert_movie_info_into_md()関数の呼び出しは1つあれば型推論してくれるので、他の2つは削りました。
def convert_movie_info_into_md(title, year, description):
"""映画の情報をMarkdown形式で返す"""
markdown = f"# {title} ({year})\n\n{description}\n"
return markdown
print(
convert_movie_info_into_md(
"エピソード4/新たなる希望",
1977,
"銀河系を舞台にした壮大なスペースオペラの始まり。",
)
)
pyrefly inferコマンドは、コードが書かれたファイルのパス、またはファイルが置かれたディレクトリのパスを指定して実行します。
pyrefly inferコマンドの実行¶$ pyrefly infer example_without_typehints.py
INFO 0 errors
pyrefly inferコマンド実行後のexample_without_typehints.pyの内容は以下のとおりです。
Pyreflyはconvert_movie_info_into_md()関数を呼び出しているコードから引数や戻り値の型を推測し、型ヒントをつけています。
pyrefly inferコマンド実行後のexample_without_typehints.py¶def convert_movie_info_into_md(title: str, year: int, description: str) -> str:
"""映画の情報をMarkdown形式で返す"""
markdown = f"# {title} ({year})\n\n{description}\n"
return markdown
print(
convert_movie_info_into_md(
"エピソード4/新たなる希望",
1977,
"銀河系を舞台にした壮大なスペースオペラの始まり。",
)
)
なお、pyrefly inferコマンドは公式ドキュメントによると、「currently under active development(現在開発中)」とのことです(バージョン0.43.1時点)。
筆者がいくつかのコードにpyrefly inferコマンドを試したところ、不可解な動作をすることがありました。
たとえば、以下のコードはpyrefly inferコマンドを2回実行しないとadd()関数の引数と戻り値両方に型ヒントがついてくれません。
pyrefly inferコマンドの挙動がおかしい例¶def add(a, b):
return a + b
print(add(2, 3))
pyrefly inferコマンドを2回実行しないと全部の型ヒントがつかない¶$ pyrefly infer example_without_typehints.py # 1回目の実行
INFO 0 errors
$ cat example_without_typehints.py # 1回目は引数にしか型ヒントがつかない
def add(a: int, b: int):
return a + b
print(add(2, 3))
$ pyrefly infer example_without_typehints.py # 2回目の実行
INFO 0 errors
$ cat example_without_typehints.py # 2回目で戻り値にも型ヒントがつく
def add(a: int, b: int) -> int:
return a + b
print(add(2, 3))
最後に¶
Pyreflyは「Pyreflyと他の型チェッカーの速度を比較する」でも紹介したtyと同じくRustで作られた型チェッカーであり、そのため両者が比較対象として取り上げられることがよくあります。 どちらも発展途上のツールであるため、今後主流になるかは不透明です。 今後の動向に注目して、私たちの開発に上手く取り入れていきたいですね。