👏

Python 3.13の新機能について調べてみた

に公開

今回は、Python3.13で導入される新機能についてまとめてみました。私自身、普段は3.11または3.12を使うことが多く、3.13についてはどのような機能が追加されるか認識していなかったので調べてみました。

追加される新機能

まず、Python3.13で導入される新機能はこちらにまとまっていますので、詳しくは参照ください。

https://docs.python.org/3/whatsnew/3.13.html#other-language-changes

よりよいインタラクティブインタプリタ

PyPyプロジェクトのコードをベースとした新しいインタラクティブシェルをデフォルトで利用するようになるようです。ユーザはREPLをターミナルから起動すると、以下の機能がサポートされます。

  • 複数行の履歴をまとめて扱える
  • helpやexitなどのREPL特有の機能を関数として呼び出さなくても利用できる
    • 今まではたとえばインタラクティブシェルから出るにはexit()としていましたが、3.13からはexitで出ることができます
  • プロンプトやトレースバックがデフォルトで色付きになる
  • Fn 1を押すとインタラクティブなhelp機能が利用できる
  • Fn 2を利用すると履歴が一覧で見れる
  • Fn 3を利用すると、大きなブロックのコードを簡単に入力するためのペーストモードになる

これらの機能をオフにするには`PYTHON_BASIC_REPL_環境変数を設定すればいいようです。

改善されたエラーメッセージ

Python3.13からエラーメッセージが改善されるようです。

  • エラーメッセージでもデフォルトで色付きになる
  • PYTHON_COLORS環境変数を利用することでコントロールでき、NO_COLOR`やFORCE_COLOR`変数もある
  • 間違ったキーワード引数を指定したときに、正しいキーワード名を提示してくれる
    • 公式で例示されているサンプルです
      >>> "Better error messages!".split(max_split=1)
      Traceback (most recent call last):
          File "<python-input-0>", line 1, in <module>
          "Better error messages!".split(max_split=1)
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
      TypeError: split() got an unexpected keyword argument 'max_split'. Did you mean 'maxsplit'?
      
  • 標準ライブラリと同じファイル名を利用してエラーが出た場合に、コンフリクト原因が明確に表示されるようになった

最後の件についてテストしてみました。たとえば以下のようなファイルがあったとします。

random.py
import random
print(random.randint(10))

これをPython3.12で実行すると以下のようになります。

Traceback (most recent call last):
  File "/Users/daisukeakagawa/Documents/Blog/python_312/random.py", line 1, in <module>
    import random
  File "/Users/daisukeakagawa/Documents/Blog/python_312/random.py", line 2, in <module>
    print(random.randint(10))
          ^^^^^^^^^^^^^^
AttributeError: partially initialized module 'random' has no attribute 'randint' (most likely due to a circular import)

エラーとしては、randomライブラリをrandom.pyで読み込もうとした結果循環参照が発生しているというエラーになっています。もちろんその通りなのですが、標準ライブラリと同じ名前を利用しているかどうかについてはエラーで言及できていません。

一方、Python3.13で実行すると以下のようになります。

Traceback (most recent call last):
  File "/Users/daisukeakagawa/Documents/Blog/python_313_new/random.py", line 1, in <module>
    import random
  File "/Users/daisukeakagawa/Documents/Blog/python_313_new/random.py", line 2, in <module>
    print(random.randint(10))
          ^^^^^^^^^^^^^^
AttributeError: module 'random' has no attribute 'randint' (consider renaming '/Users/daisukeakagawa/Documents/Blog/python_313_new/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module)

エラーを見ると

AttributeError: module 'random' has no attribute 'randint' (consider renaming '/Users/daisukeakagawa/Documents/Blog/python_313_new/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module)

となっており、標準ライブラリと同じ名前を使わないように促すメッセージが表示されます。

スレッド機能の修正

CPythonでは長きにわたりGlobal Interpreter Lock(GIL)に関する議論が起こっていました。
GILとは簡単に言えば、スレッドを実行するときに同時に実行されるスレッドを1つに限定する仕組みとなります。スレッド実行時に安全性を確保するために導入されている概念ですが、長年この機能に関してその必要性などが議論されておりました。

そこで、Python3.13では実験的にGILをオフにして利用できる機能が提供されるようです。なお、GILなし版を利用するためにはpython3.13のような従来形式のバイナリではなくpython3.13tのようなものを利用する必要があるようです。またはCPythonを--disable-gilオプションをつけてビルドしてもGILなしで実行できるようです。

実験的なJIT

CPythonをビルドするときに--enable-experimental-jitオプションをつけるとJITコンパイラーが追加され、一部のPythonコードが早くなる可能性があるということです。すでにjitを行うための仕組みがライブラリレベルで提供されていたりはしますが、ネイティブで対応される方がいいと思いますので、将来的な本格実装が楽しみです。

locals()の戻り値の変更に関して

歴史的に、locals() の戻り値を変更した場合に期待される結果は、個々のPython実装が定義する必要がありました。Python 3.13以降、ほとんどのコード実行スコープにおける CPython の従来の動作は標準化されたようですが、最適化されたスコープについては、割り当てられているローカル変数 の独立スナップショットを明示的に返すようにされたようです。
正直locals関数を普段利用しないのでこの恩恵がまだ理解できてないのでいずれ試してみたいと思います(詳しく説明できず申し訳ないです。

モバイル環境の対応

iOSおよびAndroidについて以下の条件下で対応されたようです

  • arm64-apple-iosおよびarm64-apple-ios-simulatorをターゲットティア3とし、PEP11でサポート対象となる
  • aarch64-linux-androidおよびx86_64-linux-androidをターゲットティア3とし、PEP11でサポート対象となる

具体的にどう利用できるかについてはまた別途解説記事を作れたらと思っています。

まとめ

個人的にはインタプリタの強化が魅力的かなと思います。特に色付きの表示によって可読性が増したこと、エラーメッセージがリッチになりデバッグがしやすくなったことが大きい要素かなと思います。

しかしまだまだわからない機能があったりするので、継続してPythonについて学習していきたいと思っています。もし間違っているところとか補足とかあればどんどんコメントお願いします!

Discussion