はじめに
Python 3.5から What's Newの内容をまとめる記事を投稿してきました。
リリースサイクルが1年になり、この前3.9が出たばかりと思ったらもう3.10のa2が出ていました(汗)。ここで書いているように、正式版がでるのと同時に次のα版がでるのでまあ予定通りなのですが、ちょっとペースが早い (^^; (←この記事を書き始めたころのコメントです。)
それでもやはり次のリリースで何が載ってくるのかは気になるので抜粋してまとめていきたいと思います。なお、3.9の次のバージョンは4.0ではなく3.10です(笑)。まずはいつもの開発ロードマップ(PEP-619)。
- 3.10.0 開発開始: 2020-05-18 (完了)
- 3.10.0 alpha 1: 2020-10-05 (完了)
- 3.10.0 alpha 2: 2020-11-02 -> 2020-11-04 (完了)
- 3.10.0 alpha 3: 2020-12-07 (完了)
- 3.10.0 alpha 4: 2021-01-04 (完了)
- 3.10.0 alpha 5: 2021-02-03(完了)
- 3.10.0 alpha 6: 2021-03-01(完了)
- 3.10.0 alpha 7: 2021-04-06(完了)
- 3.10.0 beta 1: 2021-05-03(完了)
- 3.10.0 beta 2: 2021-05-31(完了)
- 3.10.0 beta 3: 2021-06-17(完了)
- 3.10.0 beta 4: 2021-07-10(完了)
- 3.10.0 candidate 1: 2021-08-03(完了)
- 3.10.0 candidate 2: 2021-09-07(完了)
- 3.10.0 final: 2021-10-04 (完了!)
予定通り、3.9からちょうど1年後の2021年10月に3.10がでました。
更新履歴
2021-10-04
- 2021-10-04にリリースされた 3.10.0をベースに改定しました。
- 「PEP-626:デバッグなどで正確な行番号を表示」を追加しました
- 「PEP-563:アノテーションの遅延評価がデフォルトになる」の導入が延期されたので記述を変更しました。
2021-05-04
- 2021-05-03にリリースされた 3.10 beta 1をベースに改定しました。
- 構造的パターンマッチングについて追記
- OpenSSL 1.1.1以上が必須な件を追記
2021-01-24
- 2021-01-04にリリースされた 3.10 alpha 4をベースに改定しました。
- 廃止予定に PEP-623 (Unicode内部実装関連)を追加
- 「PEP-612: 引数仕様変数」に関して別記事に書き、それへのリンクを追加しました
2020-11-07
- 最初のバージョン。a2が 2020-10-04にリリースされましたが、そのwhat's new をベースに書いています。
注目した新しい機能
PEP 634: 構造的パターンマッチング
Python 3.10の目玉機能だと思いますが、パターンマッチングの機能がPythonにやってきます。RustやScalaではお馴染みの機能で、switch文がないPythonにとっては今後多用されることになるのではないでしょうか。
→ 別記事にしました: Python3.10の新機能(2) - Pythonにmatch文がやってくる
PEP 626: デバッグなどで正確な行番号を表示
実行時エラーが起きた時にはスタックトレースが表示されますが、そこにある行番号はデバッグする上でとても重要な情報になります。これまでの実装でもほとんどの場合で正しい行番号を表示していましたが、そうではない場合もいくつかありました。それを修正するのがこのPEPです。
これまでも実行中のバイトコードに対応するソースコードの行番号はフレームオブジェクトのf_lineno
という属性に保持されていました。それに加えて co_lines()
というメソッドが追加され、バイトコードと行番号の関連がより明確にわかるようになっています。
例えば以下のようなコードを例に挙げてみます。便宜上、行番号も表示しています。
1 from dis import dis
2
3 def f(a):
4 try:
5 if a:
6 print("yes")
7 else:
8 print("done")
9 finally:
10 print("done")
11
12 if __name__ == "__main__":
13 code = f.__code__
14 print("==co_lines==")
15 print(list(code.co_lines()))
16 print("\n==bytecode==")
17 dis(code.co_code)
これを実行すると以下の出力が得られます。
==co_lines==
[(0, 2, 4), (2, 6, 5), (6, 16, 6), (16, 26, 8), (26, 38, 10), (38, 40, 6), (40, 62, 10)]
==bytecode==
0 SETUP_FINALLY 25 (to 52)
2 LOAD_FAST 0 (0)
4 POP_JUMP_IF_FALSE 8 (to 16)
6 LOAD_GLOBAL 0 (0)
8 LOAD_CONST 1 (1)
10 CALL_FUNCTION 1
12 POP_TOP
14 JUMP_FORWARD 11 (to 38)
>> 16 LOAD_GLOBAL 0 (0)
18 LOAD_CONST 2 (2)
20 CALL_FUNCTION 1
22 POP_TOP
24 POP_BLOCK
26 LOAD_GLOBAL 0 (0)
28 LOAD_CONST 2 (2)
30 CALL_FUNCTION 1
32 POP_TOP
34 LOAD_CONST 0 (0)
36 RETURN_VALUE
>> 38 POP_BLOCK
40 LOAD_GLOBAL 0 (0)
42 LOAD_CONST 2 (2)
44 CALL_FUNCTION 1
46 POP_TOP
48 LOAD_CONST 0 (0)
50 RETURN_VALUE
>> 52 LOAD_GLOBAL 0 (0)
54 LOAD_CONST 2 (2)
56 CALL_FUNCTION 1
58 POP_TOP
60 RERAISE 0
co_lines()
は3値のタプルを返すジェネレータで、それぞれ (バイトコードの開始オフセット、バイトコードの終了オフセット, 行番号)
となっています。したがって、1つ目の (0, 2, 4)
は「バイトコードの0
番目から2
番目(の手前)までは行番号4
」ということになります。つまりソースコードを見るとそれは try
文であることがわかります。つまり、
0 SETUP_FINALLY 25 (to 52)
がtry
の実行ということになります。同様に二つ目の (2, 6, 5)
は「バイトコードの2
番目から6
番目(の手前)までは行番号5
」ということになり、
2 LOAD_FAST 0 (0)
4 POP_JUMP_IF_FALSE 8 (to 16)
がif
文の実行ということになります。
なお、co_lines()
の返り値をみるとelse
やfinally
の行に相当する項目がないことに気がつくと思います。これらの行は実際には実行されることのない文で、その他にdel
、global
、nonlocal
などがそれにあたります。
PEP 563: アノテーションの遅延評価がデフォルトになる
Python-3.7の新機能として「アノテーションの評価を遅らせる」というのを紹介しましたが、その動作がデフォルトになりました デフォルトになるのは見送られました。
これまでは遅延評価を有効にするには
from __future__ import annotations
というimport文を入れる必要がありましたが、3.10からはその必要がなくなるはずでした。実際、α版には取り入れられたのですが、その後、過去資産で動かなくなるものが多々あるなど影響範囲が大きい事がわかり、導入が延期されたとのことです。詳細はこちらのブログ記事をご参照ください。@methaneさん、ご指摘ありがとうございました。
PEP 613: 型エイリアスのアノテーション
PEP 484で型エイリアス(型に別名をつける)が導入されましたが、トップレベルでの代入式で表現されるので通常の変数への代入と見分けがつきにくいという問題がありました。型エイリアスであることを明確にするためにTypeAlias
というアノテーションが追加されます。
例えばこれまでは
IntType = int
と書いていたものが
IntType: TypeAlias = int
という風に書けるようになります。
PEP 604: 共用体型オペレータ
これまた型関係の変更ですが、2つ以上の型を取る変数の型アノテーションをする場合、これまでは
number: Union[int, float]
と書かなければならなかったところが
number: int | float
と書けるようになります。TypeScriptなどでも使われている記法を取り入れた感じですね。
PEP-612: 引数仕様変数
→ 別記事にしました: Python3.10の新機能(1) - 引数仕様変数 (Parameter Specification Variables)
PEP 618: zip関数の追加パラメータ
zip()
関数にstrict
というパラメータが追加され、これがTrue
の時にはzipする2つのイテラブルが同じ長さであることをチェックします。長さが違う場合には ValueError
例外が送出されます。
##その他の言語の変更
-
int
型の変数にbit_count()
というメソッドが追加されました。これは整数の数値をバイナリ表現した場合の1
の数を返すというものです。これは、Population Count (or pop count)という呼び方もされるようですが、基本はbin(a).count('1')
とやっていることは同じで、より高速に処理ができるようになったということのようです。 -
辞書型のメソッド
keys()
、values()
、items()
が返すビューオブジェクトにmapping
という属性が追加され、元の辞書型データへアクセスできるようになりました。 -
DecimalおよびFractionは整数引数の値として使えなくなります。例えば以下のようなコードは Python-3.9.では
DeprecationWarning
が出されていましたが、python-3.10からエラーになります。from decimal import Decimal i = Decimal(97) print(chr(i))
新規に追加されたモジュール
3.10では追加モジュールは無いようです。
モジュールの改善
base64
RFC-4648で定義されている拡張Hexアルファベットをサポートするためにbase64.b43hexencode()
とbase64.b43hexdecode()
が追加されました。通常のBase32のアルファベットは他の文字との見た目が似ている '0'と'1'を使わないようになっているのですが、この拡張Hexアルファベットではそれらは使用されていて、代わりにマッピングされた文字がソート順になっているという特徴があります(それで何が嬉しいのかは謎ですが)
curses
ncurses 6.1 で導入された拡張カラーを使うことができるようになります。Pythonから利用しているncursesライブラリがこれをサポートしているかどうかは curses.has_extended_color_support()
で確認することができます。
glob
glob()
とiglob()
にroot_dir
とdir_fd
パラメータが追加され、ファイル検索のルートディレクトリを指定できるようになりました。前者はパス風オブジェクトで、後者はルートディレクトリのファイルディスクリプタを指定します。
ssl
OpenSSL 1.1.1以降が必須になりました(PEP-644)
types
types.EllipsisType
、types.NoneType
、types.NotImplementedType
が(再)導入されました。
最適化
-
str()
bytes()
bytesarray()
が速くなりました(小さなオブジェクトの場合30-40%) -
runpy
モジュールがインポートするモジュールの数が少なくなり、python -m モジュール名
で実行した場合に起動時間が平均で 1.3倍速くなりました
廃止予定
- このバージョンから、python2.7との互換性のために残されていた古いインポート方法が廃止予定になります。
-
find_loader()
、find_module()
、load_module()
、__package__
属性、__loader__
属性は将来のバージョンで消去されます。 - Unicodeの内部実装に手が入り、PEP-393で導入されたC言語のAPIとそれらのAPIで使われていたunicodeオブジェクト内のデータが廃止予定になります。元々はPython 4.0で削除予定でしたが、4.0のスケジュールが立っていないため、3.12で削除することになりました。これによって文字列一つあたり8バイトの節約になりAPI呼び出時のオーバーヘッドも削減できます (PEP-623)
機能削除
-
complex
クラスの__int__
,__float__
,__floordiv__
,__mod__
,__divmod__
,__rfloordiv__
,__rmod__
,__rdivmod__
メソッドが消去されました。
まとめ
Python 3.10の変更点についてまとめてみました。b1になったので仕様はこれでFixだと思います。紹介しきれていない変更についてまた後ほど追記するかも知れませんが、3.11の開発も始まりますし、そちらも徐々に追いかけていきたいと思います。