最近のPython-dev(2017-12)
バックナンバー: 9月号 | 8月号 | 6月号 | 5月号 | 4月号 | 3月号 | 2月号 | 1月号
@methane です。 ISUCON があってしばらく間が空いてしまいました。コミットやML上の議論も追えてないのですが、1月末にPython 3.7のbeta1 (=feature freeze)が予定されているために、Python 3.7 を目標にしている PEP たちがたくさんacceptされたので、それらを紹介しておきます。PEP 540 UTF-8 mode
https://www.python.org/dev/peps/pep-0540/
PEP 538 (locale coercion) とセットで、私が BDFL-delegate (PEP を accept する責任者) になった PEP です。
この PEP は当初はかなりのボリュームが有ったのですが、すでに PEP 538 を accept したので、それを補完する機能として大幅にシンプル化しました。
PEP 538 では、起動時に locale が C であったときに、 LC_CTYPE を C.UTF-8 などへの変更を試みます。 また、C locale では標準入出力のエラーハンドラが surrogateescape になり、例えば stdin から読んだ文字列をそのまま stdout に書く場合などに非ASCII文字に対してもバイト透過な振る舞いをするのですが、それを C.UTF-8 などの coercion ターゲットとなる locale にも適用します。
PEP 540 も、 locale を変更しない以外は全く同じ振る舞いをするようになりました。具体的には次のとおりです。
- stdin, stdout の encoding/error handler が UTF-8/surrogateescape になる
- sys.getfilesystemencoding() と locale.getpreferredencoding() が UTF-8 を返す
PEP 538 と違って実際の locale は変更されないので、例えば readline で日本語入力はできないままですが、C locale 以外存在しないコンテナ等で Python を動かすときにデフォルトでUTF-8を使ってほしいというような用途にはこれで十分です。
PEP 563 Postponed Evaluation of Annotations
https://www.python.org/dev/peps/pep-0563/
from __future__ import annotations
を書くことで、関数アノテーションが評価されず、ただの文字列になります。とはいえ、ソースを読むときに構文としてはチェックされるので、任意の文字列がかけるわけではありません。
これにより、アノテーションを書くことによる性能のオーバーヘッドを減らす効果があるのと、アノテーション部分の名前解決のための forward references が不要になって書くのが楽になるという効果があります。
この動作は Python 4 からデフォルトになる予定なので、 Python 3.7 に移行した人は早めにこの動作を有効にすることをおすすめします。
個人的には、実行時に評価されなくなることで、Python の構文を実行時には許されない形で利用したり、あるいはアノテーション部分でしか利用できない構文を追加するという進化への道が開けたという点でも期待しています。例えば現在 Union[int, str]
と書いている部分を int or str
あるいは int | str
と書けるようにする提案ができるかもしれません。(前者は評価するとただの int になり、後者は評価すると | が処理できずに TypeError になる)
PEP 560 Core support for typing module and generic types
https://www.python.org/dev/peps/pep-0560/
いままで type hint は Python 3 で追加された関数アノテーション以外には特別な Python に対する機能追加を必要としないように設計されてきましたが、 typing がある程度の成功を収めて来ているので、そろそろ typing の問題を解決するために Python 自体に手を入れてもいれようというのがこの PEP です。
例えば、 typing.List
は class List(list, MutableSequence[T], extra=list): ...
として宣言されています。
この MutableSequence[T]
の部分ですが、親クラスになるためにクラスでないといけないという制限があります。そのために実際に親クラスになってしまうので実際にメソッドを提供していないクラスが大量にMROに入りメソッド呼び出し性能のオーバーヘッドが大きくなるという問題があります。また、 MutableSequence 自体もクラスなので、それに対して [T]
と書けるようにするためにメタクラスが使われています。
このために現在の typing は大量のメタクラスハックを必要とし、実行時オーバーヘッドもかかり、 import typing も遅くなり、また他のメタクラスとの衝突解決の手間が発生するという欠点を背負っています。
これを解決するために、 Python に次の機能を追加します。
- class 文の親クラスリスト部分に、 type オブジェクトではない
__mro_entries__
メソッドを持つオブジェクトを書くことができる __class_getitem__
メソッドを定義すると、メタクラスを使わなくてもMyClass[int]
のようにクラスに添え字を書くことができる
これらの機能は typing モジュール以外から使えないというわけではありませんが、 typing 以外の用途での利用は非推奨になっています。
とはいえ、 __class_getitem__
については、最近のメタクラスを使わなくてもクラスの振る舞いをカスタマイズできる流れに添っていて黒魔術感も比較的少なめなので、本当にクラスオブジェクトに添え字アクセスが必要な場面であれば、typing 以外で使っても良いんじゃないかな。
PEP 561 -- Distributing and Packaging Type Information
https://www.python.org/dev/peps/pep-0561/
Typing が本格的に使われていくためには、サードパーティーライブラリの型情報をどうやって配布・利用するかを決めなければなりません。ということでそれを決めたのがこの PEP です。
PEP 562 -- Module getattr and dir
https://www.python.org/dev/peps/pep-0562/
モジュールに __getattr__
関数を定義して遅延ロードや利用時warningなどを実現する仕組みです。
また、遅延ロードされる名前を提供するために __dir__
を利用することもできます。
個人的には、 import asyncio
で芋づる式に multiprocessing まで import されているのを、 concurrent.futures.ProcessPoolExecutor を遅延ロードすることで解消したいと思っています。
PEP 565 -- Show DeprecationWarning in main
https://www.python.org/dev/peps/pep-0565/
Python には廃止予定のAPIについて警告するための DeprecatedWarning がありますが、これはPython製アプリケーションのユーザーにとってはほぼ無意味で混乱させるものなので、現在はデフォルトで表示されないようになっています。
しかし、 Python 開発者でもこの警告を有効にしていない人が多いために、DeprecationWarning に気づかれないという悩ましい状況も発生しています。
PEP 565 はこのバランスを少しだけ調整する提案です。 __main__
モジュールにおいてだけ、 DeprecationWarning をデフォルトで表示するようにします。
__main__
モジュールとは、インタラクティブシェルや Python インタプリタに渡された実行ファイルのことです。そこで直接廃止予定のAPIが呼ばれたときだけ DeprecationWarning が表示されるようになります。
これにより、開発者がAPIの使い方を調べるなどの目的でインタラクティブシェルで廃止予定のAPIを実行したときに Warning に気づけるようになると期待できます。
とはいえ、これの効果は限定的なので、Python開発者は -Wdefault
オプションを使うか、 PYTHONWARNINGS=default
と環境変数を設定しておきましょう。
-X dev option
https://docs.python.org/dev/using/cmdline.html#id5
上で紹介した -Wdefault
オプションに加えて、 Python 拡張モジュール開発者向けのものも含めて、幾つかの開発者向けオプションをまとめて有効にするオプションとして -X dev
オプションが追加されました。
また、 PYTHONDEVMODE=1
という環境変数でも dev mode を有効にできるようになります。
PEP 557 -- Data Classes
https://www.python.org/dev/peps/pep-0557/
ちょうど Qiita に紹介記事があったのでそちらを参照してください。