最近の Python-dev (2017-01)
@methane です。 compact dict が Python 3.6 が9月(ベータになる直前)にマージされ、それのおかげで推薦をもらい 10月ごろから Python の Core Developer になりました。
「PythonのフルタイムコミッタとしてKLabに雇われている」という訳ではないのですが、 もともと自己裁量で業務時間の大半をOSSへの貢献やコードを読むことに費やし、特にこの3ヶ月位は Python ばかり触っていたので、実質的には近い状態です。
そちらでの活動をあまり日本で共有する機会がないので、 Money Forward の卜部さんが書かれている 最近の ruby-core という記事をリスペクトして、 最近の Python の開発状況を紹介する記事を書いてみたいと思います。
Python 3.6 リリース
12/23 に Python 3.6 がリリースされました。紹介しきれないほどたくさんの重要な改善がされていますが、 多分 (Python を普段使わない人にも) 一番わかり易いのは f-string でしょう。
f-string は文字列の中に式を書くことができる機能です。多くのLLが持っている機能なのですが、乱用すると簡単にメンテしにくいコードが書けてしまうので、
従来 "{foo.name} = {foo.value}".format(foo=foo)
と書いていたのを f"{foo.name} = {foo.value}"
とするように、
純粋に .format(name=name)
の置き換えとして使い始めることをおすすめします。
私が主に貢献したのは compact dict と asyncio の高速化です。余談ですが、 Python 3.6 の2日後にリリースされた Ruby 2.4.0 にも compact dict とほぼ同一の新しいハッシュの実装が導入されました。偶然ですね。
(主に) C locale での UTF-8 サポート改善
Linux では Python はターミナル、標準入出力、ファイルパスなどのエンコーディングを locale を見て決定します。
ですが、 POSIX で C locale (POSIX locale とも言う) は ASCII を使うと決められているために、非 ASCII 文字を使うと UnicodeEncodeError を発生させてしまいます。標準入出力に関しては PYTHONIOENCODING という環境変数で制御できるのですが、 コマンドライン引数とファイルパスのエンコーディングは設定できませんでした。
C locale はデフォルトのロケールなので、 crontab に指定しなかったとき、 ssh が LANG=ja_JP.UTF-8
を送った接続先の
サーバーが ja_JP.UTF-8
ロケールを持っていなかったときなどに意図せず使われます。翻訳されたエラーメッセージなんて
(英語で報告しにくいから)見たくないとか、コマンドの挙動が変わるのが嫌だからという理由で意図的に C locale
を使うエンジニアも多いでしょう。コンテナや組み込みなどの小さなLinux環境を作るときは容量削減のために C 以外のロケールが
そもそも存在しないこともあります。
そういうさまざまな理由で C locale 上で Python を使うと、 UnicodeEncodeError が発生する事があり、特に Python 開発者ではない Python 製のツールを使ってるだけの人を困らせることになります。
Python は広いユーザー層を抱えているので locale の使われ方も様々なのですが、それでも本当に ASCII だけを使いたくて C locale を使っているユーザーはほとんどいないだろうということで、 C locale でデフォルトで UTF-8 を使うための提案がされています。
(まだ提案段階なので、 Python の開発ブランチをチェックアウトしても使えません)
PEP 540: Add a new UTF-8 mode
Python に UTF-8 mode を追加しようという提案です。 UTF-8 mode では locale が指定するエンコーディングを無視して、 ファイルパスと標準入出力が UTF-8 になります。
このモードは厳密に言えば disabled, enabled, strict の3つの状態があります。 enabled と strict の違いは、 UTF-8 でない バイト列を透過的に扱うための surrogate escape を使うか、 UTF-8 でない バイト列はエラーにするかです。
C locale ではデフォルトでこのモードが enabled になり、UTF-8でないファイルパスや標準入出力への読み書きが可能になります。 今時はめったに使わないかも知れないですが、外部のファイルシステムをマウントしたときとかに嬉しいはずです。
C 以外の locale では locale 指定のエンコーディングが strict で使われるので、 UTF-8 以外のデータはエラーを発生させます。 こちらは UTF-8 以外は除去したいときに、誤って文字化けしたデータを作るのを早めに気づいて止めたいときに便利です。
このモードは PYTHONUTF8
という環境変数や -X utf-8
というオプションで制御できるので、 locale を無視したい人は
.bashrc
などに export PYTHONUTF8=1
と書くか、 /etc/environment
に PYTHONUTF8=1
と書いておくと良いでしょう。
PEP 538: Coercing the legacy C locale to C.UTF-8
こちらは、環境変数が指定しているのが C locale だったときに、 locale を C.UTF-8 に(システムが対応していれば)変更してしまおうという提案です。
これにより、 Python 本体だけでなく、別のライブラリも ASCII や latin1 ではなく UTF-8 で動作するようになることが期待されます。
例えば Python の REPL でも使われている readline が該当するので、 Android 上の Python の REPL で 何の設定をしなくても快適に UTF-8 を扱えるようになったという報告があります。
新しい呼び出し規約の拡大 (METH_FASTCALL
)
従来、Cの世界から見た Python の関数呼び出しとは、順序引数をタプルで、キーワード引数を dict で渡すものでした。
Python 3.6 でタプルの代わりにただの配列の先頭ポインタ+順序引数の数を渡す呼び出す規約が登場し、呼び出し側が スタックに積んだ引数をタプルに詰めなくてもそのまま渡せるようになりました。
現在、C言語で作った「Pythonから呼べる関数」をこの新しい呼び出し規約に対応させる作業が進んでいて、重要な部分はあらかた対応が終わりました。
また、かなり内部の話になるのですが、 PyMethodDef
(名前, 呼び出し規約を示すフラグ, 関数ポインタでなる構造体) で作成する関数やメソッド以外に、
オブジェクト自体が呼び出し可能 (Python に詳しい人なら、 operator.itemgetter()
が返すオブジェクトといえば伝わるかも知れません) な型があり、そちらは型のメタデータとなる構造体に関数ポインタ tp_call
が含まれています。
PyMethodDef
の方は従来からフラグを使って複数の呼び出し規約に対応していたので、C言語から呼ぶときは専用のAPIを使っていました。 一方tp_call
の方は今までタプルと dict を受け取る標準の呼び出し規約しかサポートしていなかったので、外部のライブラリがAPIを経由せずに関数ポインタを直接呼び出ししてしまっている可能性があります。
そこで互換性維持のために tp_fastcall
という関数ポインタを新たに追加し、 tp_fastcall
を用意している型には自動的に tp_call
に変換するための関数を埋めるようにするパッチがレビュー中です。
細かいようですが、 Python の世界から見たら1つの呼び出しの引数が、C言語の世界では複数の関数の間で引き渡される事があるので、内部に新方式と従来方式が混ざっていると余計な変換が何度も発生する可能性があります。
Python 3.7 では内部での引数の渡し方が新方式に統一されて新しい呼び出し規約の実力が発揮できると思います。
Github へのマイグレーション
去年の1月にアナウンスされてから着々と準備が進んできていた、 Mercurial から Git、 hg.python.org から Github への移行ですが、着々と準備が進んでいるようです。
1/17 に Python 3.4.6 と 3.5.3 がリリースされ、 migration window と宣言されていた期間が始まったので、そろそろ実際に移行するスケジュールがアナウンスされると思います。1月中に移行できると良いなー。