はじめに
以前、Python3.5の新機能という記事を書いたが、3.6もα版が出て来たので、3.6の機能を先取りして確認してみようと思う。
開発ロードマップ(PEP-494)によると
- 3.6.0 alpha 1: 2016-05-17 (完了)
- 3.6.0 alpha 2: 2016-06-13 (完了)
- 3.6.0 alpha 3: 2016-07-11 (完了)
- 3.6.0 alpha 4: 2016-08-15 (完了)
- 3.6.0 beta 1: 2016-09-12 (完了・新機能追加はここまで)
- 3.6.0 beta 2: 2016-10-03
- 3.6.0 beta 3: 2016-10-31
- 3.6.0 beta 4: 2016-11-21
- 3.6.0 candidate 1: 2016-12-05
- 3.6.0 candidate 2: 2016-12-12 (必要であれば)
- 3.6.0 final: 2016-12-16
となっていて、先はまだまだ長い。最終版が出るのは12月16日。クリスマス前だ。新機能の追加も9月のベータが出るまで続くのでそれまではドンドン変わっていくと思うが、変更がある度にこの記事をアップデートしていこうと思う。その方が一気に見るよりも楽だし(^^;
という事で、今回参照したのは3.6.0b1で、ここのドラフト版リリースドキュメントを参考にした。
試す場合にはpyenvを使って
pyenv install 3.6.0b1
pyenv local 3.6.0b1
でどうぞ。
更新履歴
2016.07.16
- 確認に使ったバージョンを 3.6.0a2から3.6.0a3に変更
- (それ以外、気がついた変更なし...)
2016.10.01
- 確認に使ったバージョンを 3.6.0b1に変更
- Betaになりこれ以上の仕様変更は無いためタイトルから"(a3版)"を削除
- 「新たな文法の導入」に global/nonlocalの変更、PEP515, PEP526, PEP525, PEP530 を追加
- 「セキュリティの改善」を追加
- 「Windowsでの改善」にPSP529, PEP528他を追加
- 「新規ビルトイン機能」を追加
- 「新機能」に追加多数
- 「その他の言語の変更」に記述追加
- 「改善されたモジュール」に記述追加
- 「廃止候補」に「廃止予定のビルドオプション」を追加
変更内容
リリースハイライト
新たな文法の導入
-
global
とnonlocal
はそのスコープで最初にその変数を使う前に置かないとダメになった(これまでは警告のみ) - PEP-498 書式化文字列リテラル
-
PEP-515 数値リテラルの中に
_
を入れられる様になった - PEP-526 変数にアノテーションする記法の導入
- PEP-525 非同期ジェネレーターの導入
- PEP-530 非同期内包表記の導入
PEP-498、PEP-515、PEP-526は「新機能」のところで更に詳細に触れている。
セキュリティの改善
- Linux上で、os.urandom()はシステムのurandomエントロピープールが初期化されるまでブロックすることになった。詳細な論拠はPEP524(https://www.python.org/dev/peps/pep-0524/)参照。
-
hashlib
とssl
モジュールがOpenSSL 1.1.0をサポート -
ssl
のデフォルト設定と機能セットがよりセキュアなものに -
hashlib
モジュールが新たなハッシュ関数(BLAKE2、SHA-3、SHAKE)と鍵導出関数scrypt()
をサポート
Windowsでの改善
- PEP529(https://www.python.org/dev/peps/pep-0529/) WindowsのファイルシステムエンコーディングをUTF-8に変更
- PEP528(https://www.python.org/dev/peps/pep-0528/) WindowsのコンソールエンコーディングをUTF-8に変更
- これまで py.exeをコマンドラインで使う時には、バージョン指定が無いとPython2を優先させていたのだが、今後はPython3になる。
-
python.exe
とpythonw.exe
がロングパス対応になり、ファイルパスの260文字制限がなくなった -
._pth
ファイルにモジュールのサーチパスを書くことができるようになった -
PYTHONHOME
が環境変数で設定されない場合、Python36.zip
の位置でそれを推測するようになった
新規ビルトイン機能
- PEP-520(https://www.python.org/dev/peps/pep-0520/) クラスの属性の定義順序を保持する
- PEP-468(https://www.python.org/dev/peps/pep-0468/) キーワード引数の順序を保持する
新機能
PEP-515 数値リテラルの中に_
を入れられる様に
1000000000000000
を1_000_000_000_000_000
と書いたり出来るようになった。意味的な変更はまったくなく単純に読みやすさのためだけの_
だ。
PEP-523 フレーム評価APIの追加
フレームオブジェクトの評価はこれまでカスタマイズできなかったが、それを出来るようにするためのCレベルのAPIを追加した。これによりJITやDebuggerの実装が楽になるらしい。
PEP-519 ファイルシステムパスプロトコルの追加
従来、ファイルシステムのパスはstr
型かbytes
型で、Python標準のものも含めて、パスを扱うライブラリはその想定で作られていた。そのため、pathlibのような、パスを表現するライブラリを既存のライブラリと組み合わせて使うのが困難だった。
これを解消するためにos.PathLike
というインターフェース(仮想基底クラス)を定義した。パスを表すオブジェクトは、これを継承し、パスの文字列表現を返す__fspath__()
というメソッドを定義することで、他のライブラリがこれをパスだと認識して動作してくれることになった。
PEP-498 書式化文字列リテラル
文字列の前にf
をつけると書式化文字列になる。str.formatの書式にも似ているが、{
と}
で囲まれた部分が変数として置換される。例えばこんな感じ。
>>> name = "モンティ・パイソン"
>>> f"私の名前は{name}です"
'私の名前はモンティ・パイソンです'
これが、str.formatを使うと
>>> "私の名前は{name}です".format(name=name)
あるいは
>>> "私の名前は{}です".format(name)
としなければならなかったので、少し記述が楽になりそう。
PEP-526 変数にアノテーションする記法の導入
Pythonは明示的な型指定のない動的型付けの言語だが、そのため静的解析などをやりにくいという問題があった。それを解消するために、PEP-484(https://www.python.org/dev/peps/pep-0484/)では関数の引数に型情報を付記するという方法が提案され、Python3.5で導入された。
これをさらに拡張し、変数(クラス変数、インスタンス変数を含む)にも型情報を付けられるようにしたというのが今回の変更。従来もコメントを使えば同じように出来たが、文法の変更で対応したというのが違いになる。例えばこんな感じ。
from typing import List, Dict
primes: List[int] = [] # 整数のリスト型の例で、それを空リストで初期化
captain: str # 文字列型。初期化しない例
class Starship:
stats: Dict[str, int] = {} # クラス変数の例。Keyとして文字列、値として整数を取る辞書型
なお、この型アノテーションで何か動作が変わるわけではなく、違った型の値を代入してもエラーにはならない。あくまでも、型情報の「ヒント」であり、この情報を元に静的解析をしたりという用途に向けたものになる。
PEP-529 WindowsのファイルシステムエンコーディングをUTF-8に変更
従来はWindowsの上でBytesを使ってパスを受け渡しするとデータ欠損とかが出る場合があった。Python 3.6からはBytesを使っていたとしてもシステムのデフォルトエンコーディングでエンコードされて返ってくることになった。なお、デフォルトエンコーディングは今のところUTF-8だが、ベータ期間のフィードバックに寄って最終的に変わるかもしれないとのこと。
PEP-487 クラス生成の簡単カスタマイズ
クラスが継承された場合に、__init_subclass__(cls)
というクラスメソッドが呼ばれる事になった。この中でカスタマイズするコードを書くことが出来る。また、ディスクリプタオブジェクトの初期化時に__set_name__
というメソッドを呼ぶことになった。
PEP-528 WindowsのコンソールエンコーディングをUTF-8に変更
全てのUnicode文字を受け付けるようになり、正しくstrオブジェクトに読み込むことができるようになった。そして、sys.stdin
、sys.stdout
、sys.stderr
のデフォルトエンコーディングはUTF-8となった。
PYTHONMALLOC環境変数
PYTHONMALLOCという環境変数にある値を入れることによってPythonのメモリ割り当ての動作を変えるたりデバッグの為のフックを仕掛けることができる。
PYTHONMALLOC=debug
この設定にすると、以下のデバッグ機能が有効になる
- 新たに割り当てられたメモリ領域は
0xCB
で埋められる - 開放された領域は
0xDB
で埋められる - メモリ割り当てAPIの不正な利用が検出される。例えば
PyMem_Malloc()
で取った領域をPyObject_Free()
で開放したりした場合。 - 割り当て領域の前に書き込んだり(バッファアンダーフロー)、後に書き込んだり(バッファオーバーフロー)した場合を検出。
- メモリ割り当て関数が呼ばれた時にGIL(Global Interpreter Lock)が確保されているかどうかの確認。
PYTHONMALLOC=malloc
この設定にすると、Cライブラリのmalloc
を強制的に使うようになる。これによって、Valgrindなどの外部ツールが使えるようになる。
PYTHONMALLOC=malloc_debug
上記2つの組み合わせ
DTraceとシステムタップのサポート
--with-dtrace
付きでコンパイルすると以下のイベントを検知するマーカーが有効になる。
- 関数呼び出し、関数復帰
- ガベージコレクションの開始と終了
- 実行されているコードの行番号
この機能によってPythonをデバッグ用に再コンパイルすることなくデバッグやプロファイリングができる。
PEP-520 クラス属性の定義順序保持
クラスの属性はソースコードに記述された順序で、クラスの__dict__
属性に保持される。
PEP-468 キーワード引数順序の保持
関数のキーワード引数はその順序を保持された形で**kwargs
に渡される。
PEP-509 辞書型オブジェクトに内部バージョン導入
辞書型オブジェクトに変更が加わったときのみ更新されるバージョンを導入した。それにより、各種の最適化(性能向上)を行うことが可能になる。
その他の言語の変更
− dict()
はPyPyで由来のコンパクトな表現を使うようになり、メモリ使用量はPythono3.5と比べて20-25%少ない。そして、PEP-468のキーワード引数の順序保持はこれを使って実装されている。一方、「順序が保存される」という性質は実装依存のもので、将来的に変わる可能性があるので、それを前提にした実装はするべきではない。
-
トレースバックの長い繰り返しは省略して表記されるようになった
-
import
がモジュールを見つけられなかった場合はModuleNotFoundError
を返すようになった
新規のモジュール
(今のところなし)
改善されたモジュール
asyncio
asyncioは「provisional(暫定的な)」と定義されているので、全ての変更は3.5.xにもバックポートされる。
3.5.0からの主な変更点は以下の通り。
-
ensure_future()
関数とそれを使う関数は、すべての種類のawaitable オブジェクトを引数に指定できるようになった。 -
run_coroutine_threadsafe()
関数が新たに導入されて、他のスレッドからイベントループにコルーチンを投入できるようになった。 -
Transport.is_closing()
メソッドが追加され、トランスポートが閉じられている(あるいは閉じている途中)かが確認できるようになった。 -
loop.create_server()
メソッドはホストのリストを引数に取れるようになった。 -
loop.create_future()
メソッドが追加され、Futureオブジェクトを作成できるようになった。これによって、代替のイベントループ実装が可能になり、より速いasyncio.Futureを提供できるようになる。 -
loop.get_exception_handler()
メソッドが追加され、現在の例外ハンドラーを取得できるようになった。 -
timeout()
コンテキストマネージャによってタイムアウト処理のコードが簡単にかけるようになった。 -
StreamReader.readuntil()
メソッドが追加され、セパレータバイトで句切られたストリームを読めるようになった。 -
loop.getaddrinfo()
メソッドが改善され、アドレスが既に名前解決していれば、OS側のgetaddrinfo
を呼ばなくても良くなった。
asyncioはあまり使ったことが無かったが、この中でrun_coroutine_threadsafe()
を使ってみた。
import asyncio
@asyncio.coroutine
def wakeup(name, repeat):
for i in range(repeat):
yield from asyncio.sleep(1)
print("{}/{}: 起きた!".format(name, i))
return repeat
def target(name, repeat, loop):
future = asyncio.run_coroutine_threadsafe(wakeup(name, repeat), loop)
return future.result()
loop = asyncio.get_event_loop()
futures = [
loop.run_in_executor(None, target, "A", 1, loop),
loop.run_in_executor(None, target, "B", 2, loop),
loop.run_in_executor(None, target, "C", 3, loop),
]
loop.run_until_complete(asyncio.wait(futures))
loop.close()
ちょっとややこしいが、wakeup
というのが実行するコルーチン。1秒間寝た後に、name
で与えられた名前を名乗って「起きた!」という行をPrintするだけ。それをもう一つの引数repeat
の回数だけ繰り返す。そのコルーチンを実行するのがtarget
という関数で、その中でrun_coroutine_threadsafe
を呼んでいる。それを別々のスレッドで実行するために、run_in_executor
で実行している。
実行結果はこんなふうになるはず。
$ python asyncio_test.py
A/0: 起きた!
B/0: 起きた!
C/0: 起きた!
B/1: 起きた!
C/1: 起きた!
C/2: 起きた!
なお、上にも書いたようにこのasyncioの変更は3.5シリーズにもバックポートされ、実際もう3.5.1で実装されているようだ。実際、上の例も問題なく動く。
contextlib
コンテキストマネージャの仮想ベースクラスとしてcontextlib.AbstractContextManager
が追加され、__enter__()
と__exit__()
のデフォルト実装を提供するようになった。また、typingモジュールにも同様のクラスが追加された。
venv
venvは新たに--prompt
パラメータを受け取るようになった。これにより仮想環境時にコマンドラインプロンプトのprefixを変えられる。
datetime
datetime.strftime()
メソッドとdate.strftime()
メソッドがISO 8601の%G
、%u
、%V
をサポートするようになった。%Gと%Vは週単位表記での年と週番号(01-53)を表し、%uは週の何番目かを表す(月曜日が1で日曜日が7)。
distutils.command.sdist
default_format 属性は distutils.command.sdist.sdistから除去され、デフォルトの属性は['gztar']になった。想定外だが、この属性に依存したコードは全て修正されなければならない。
policy引数の追加された新たなメールAPIが「provisional(暫定)」ではなくなり、ドキュメントもそれを中心に書き直された。従来のドキュメントはレガシーAPIとして残されている。
email.mime
クラスやDecodedGenerator
はpolicy引数を受け取るようになった。
policyオブジェクトにmessage_factory
属性が追加され、パーサが新たなメッセージを生成する時にどのメッセージクラスを使うのか指定できるようになった。
encodings
Windows環境上で、CP_OEMCP
を使う'oem'
が追加された。また、CP_ACP
を使うmbcs
にansi
というエイリアスが加えられた。
faulthandler
Windows環境でWindows例外を発生させるハンドラーをインストールするようになった。
hashlib
hashlibはOpenSSL 1.1.0をサポートした。推奨バージョンは1.0.2以上だが、 0.9.8zc、0.9.8zh、1.0.1t と LibreSSL 2.3、2.4でもテストされている。
BLAKE2ハッシュ関数のサポートが追加され、blake2b()、blake2s()が利用できるようになった。
SHA-3ハッシュ関数 sha3_224()、sha3_256()、sha3_384()、sha3_512() と SHAKEハッシュ関数 shake_128()、shake_256()が追加された。
パスワードベースの鍵導出関数 scrypt()がOpenSSL 1.1.0以上の場合に利用可能になった。
http.client
HTTPConnection.request() と endheaders() がリクエストボディで chunked エンコーディングをサポートした。
idlelibとIDLE
idlelibパッケージが今風にリファクタリングされIDLEの見た目や操作性・視認性が向上した。変更にはファイル名の変更も含まれ、3.5までのコードはそのままだと動かない。
importlib
importlib.util.LazyLoader
がラッパーローダーの上でcreate_module()
を呼ぶようになったのでimportlib.machinery.BuiltinImporter
とimportlib.machinery.ExtensionFileLoader
がimportlib.util.LazyLoader
と一緒に使えないという制約がなくなった。
importlib.util.cache_from_source()
、importlib.util.source_from_cache()
、importlib.util.spec_from_file_location()
はパス風オブジェクトを受け取れるようになった。
json
json.load()
とjson.loads()
はバイナリを入力として受け取れるようになった。エンコードされたJSONはUTF-8、UTF-16、UTF-32のいずれかでエンコードされていなければならない。
os
close()
メソッドが提供され、scandir()
のイタレーターを明示的に閉じれるようになった。そして、scandir()
のイタレーターがコンテキストマネージャプロトコルをサポートするようになった。scandir()
のイタレーターが使い切られていない、あるいは明示的に閉じられなかった場合には、ResourceWarning
例外がデストラクタの中で発生する。これは、メモリリーク対策だと思うが、withステートメントと一緒に使えば自動で呼んでくれる。
Linuxのgetrandom()
システムコールは新たなos.getrandm()関数を介して利用可能になった。
pickle
__new__
をキーワード引数と共に呼ばなければならなかったオブジェクトの塩漬け(ピクル化)ができるようになった。これはpickle version 4以上であればこれまでもできていたが、今回の変更でversion 3以下でもできるようになったとのこと。
re
正規表現にかかる修飾子が追加された。例えば'(?i:p)ython'
は'python'
と'Python'
にはマッチするけど'PYTHON'
にはマッチしない。同様に'(?i)g(?-i:v)r'
は'GvR'
や'gvr'
にはマッチするけど'GVR'
にはマッチしない。
readline
set_auto_history()
が追加され、履歴への自動追加有無が制御できるようになった。
rlcompleter
rlcompleterはreadlineのcompletion(補完機能)。ひとつ目の変更は、アンダースコア('_')で始まるモジュール変数・メソッド・属性を補完のリストから外したこと。と言っても分かりにくいので、例を。これまでは、Pythonを対話モードで立ち上げて、"int."と打ち込んだ後にTABキーを2回押すとこうなった
$ python
Python 3.5.2 (default, Jul 7 2016, 23:37:57)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> int.<TAB><TAB>
int.__abs__( int.__dir__( int.__hash__( int.__mul__( int.__reduce__( int.__rtruediv__( int.__xor__(
int.__add__( int.__divmod__( int.__index__( int.__name__ int.__reduce_ex__( int.__rxor__( int.bit_length(
int.__and__( int.__doc__ int.__init__( int.__ne__( int.__repr__( int.__setattr__( int.conjugate(
int.__base__( int.__eq__( int.__instancecheck__( int.__neg__( int.__rfloordiv__( int.__sizeof__( int.denominator
int.__bases__ int.__flags__ int.__int__( int.__new__( int.__rlshift__( int.__str__( int.from_bytes(
int.__basicsize__ int.__float__( int.__invert__( int.__or__( int.__rmod__( int.__sub__( int.imag
int.__bool__( int.__floor__( int.__itemsize__ int.__pos__( int.__rmul__( int.__subclasscheck__( int.mro(
int.__call__( int.__floordiv__( int.__le__( int.__pow__( int.__ror__( int.__subclasses__( int.numerator
int.__ceil__( int.__format__( int.__lshift__( int.__prepare__( int.__round__( int.__subclasshook__( int.real
int.__class__( int.__ge__( int.__lt__( int.__qualname__ int.__rpow__( int.__text_signature__ int.to_bytes(
int.__delattr__( int.__getattribute__( int.__mod__( int.__radd__( int.__rrshift__( int.__truediv__(
int.__dict__ int.__getnewargs__( int.__module__ int.__rand__( int.__rshift__( int.__trunc__(
int.__dictoffset__ int.__gt__( int.__mro__ int.__rdivmod__( int.__rsub__( int.__weakrefoffset__
>>> int.
これが、3.6からはこうなる。
ython 3.6.0a3 (default, Jul 16 2016, 00:35:58)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> int.
int.bit_length( int.conjugate( int.denominator int.from_bytes( int.imag int.mro( int.numerator int.real int.to_bytes(
_
から始まる名前が補完候補から外されている。それらを表示したければ、_
を打ち込んでから<TAB><TAB>
。
>>> int.__
int.__abs__( int.__dict__ int.__getattribute__( int.__lt__( int.__prepare__( int.__ror__( int.__subclasscheck__(
int.__abstractmethods__ int.__dictoffset__ int.__getnewargs__( int.__mod__( int.__qualname__ int.__round__( int.__subclasses__(
int.__add__( int.__dir__( int.__gt__( int.__module__ int.__radd__( int.__rpow__( int.__subclasshook__(
int.__and__( int.__divmod__( int.__hash__( int.__mro__ int.__rand__( int.__rrshift__( int.__text_signature__
int.__base__( int.__doc__ int.__index__( int.__mul__( int.__rdivmod__( int.__rshift__( int.__truediv__(
int.__bases__ int.__eq__( int.__init__( int.__name__ int.__reduce__( int.__rsub__( int.__trunc__(
int.__basicsize__ int.__flags__ int.__instancecheck__( int.__ne__( int.__reduce_ex__( int.__rtruediv__( int.__weakrefoffset__
int.__bool__( int.__float__( int.__int__( int.__neg__( int.__repr__( int.__rxor__( int.__xor__(
int.__call__( int.__floor__( int.__invert__( int.__new__( int.__rfloordiv__( int.__setattr__(
int.__ceil__( int.__floordiv__( int.__itemsize__ int.__or__( int.__rlshift__( int.__sizeof__(
int.__class__( int.__format__( int.__le__( int.__pos__( int.__rmod__( int.__str__(
int.__delattr__( int.__ge__( int.__lshift__( int.__pow__( int.__rmul__( int.__sub__(
>>> int.__
それから、幾つかのキーワードを補完した後にスペース(' ')かコロン(':')が付くようになった。例えば、wi
と打ち込んで<TAB>
を押すとwith
とスペース付きで補完されるし、tr
と打ち込んだから<TAB>
するとtry:
となる。地味に便利。
あと、これまで表示されなかった@property
で作られた属性とかの補完ができるようになったともあるが、これはよく判らなかった。
site
sys.pathにパスを追加する際に重複チェックしているが、それがうまく動かない場合の修正っぽい。
sqlite3
sqlite3.Cursor.lastrowid
は最後に変更した列の列IDを返すが、これまでINSERTを実行した時のみ有効だったが、REPLACEを実行した時にも取れるようになった。
socket
ioctl()
関数でSIO_LOOPBACK_FAST_PATH
が使えるようになり、Windows環境(Win8以上)でTCP loopbackのパフォーマンスを向上させることができるようになった。
getsockopt()の定数SO_DOMAIN
、SO_PROTOCOL
、SO_PEERSEC
、and SO_PASSSEC
がサポートされた。
アドレスファミリー AF_ALGがサポートされ、LinuxカーネルのCrypto APIを利用できることになった。
socketserver
socketserverモジュールに基づくサーバー(例えばhttp.server
, xmlrpc.server
やwsgiref.simple_server
で定義されている)がコンテキストマネージャプロトコルをサポートするようになった。
StreamRequestHandler
クラスのwfile
属性がio.BufferedIOBase
のwritable
インターフェイスを実装した。特に、write()
はデータを全て送ることが保証されるようになった。
ssl
sslはOpenSSL 1.1.0をサポートした。推奨バージョンは1.0.2以上だが、 0.9.8zc、0.9.8zh、1.0.1t と LibreSSL 2.3、2.4でもテストされている。
3DES はデフォルト暗号スイートから外された。また、ChaCha20 Poly1305 暗号スイートは正しい場所に置かれることになった。
SSLContextのデフォルトコンフィギュレーションはより良いオプションと暗号を使うようになった。
SSLセッションはクライアント側から相手側にSSLSessionを使ってコピーできるようになった。TLSセッションの再開が速度改善された。
全ての定数やフラグはIntEnumからIntFlagsへ変更された。
SSLContext作成時に引き渡すパラメータとして、Server-sideのみ、Client-sideのみのプロトコルが追加された。
サブジェクトの別名拡張領域にGeneralリソースIDを入れてもシステムエラーにならなくなった。
subprocess
subprocess.Popen
で作られた子プロセスが実行中にのPopenオブジェクトを消去しようとすると、ResourceWarning
例外が起こるようになった。
telnetlib
Telnet
がコンテクストマネージャプロトコルを実装。
tkinter
tkinter.Variable
クラスにtrace_add()
trace_remove()
trace_info()
メソッドを追加し、Tclの古いAPIを使っていた実装を置き換えた。
traceback
トレースバックの長い繰り返しは省略して表記されるようになった。例えば自己ループする関数を実行するとこのようになる。
>>> def f(): f()
...
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in f
File "<stdin>", line 1, in f
File "<stdin>", line 1, in f
[Previous line repeated 995 more times]
RecursionError: maximum recursion depth exceeded
typing
contextlib.AbstractContextManager
の為のtyping.ContextManager
クラスが追加された(前述のとおり)。
unicodedata
内部のデータベースが Unicode 9.0.0にアップグレードされた。
unittest.mock
Mock
クラスにMock.assert_called()
とMock.assert_called_once()
が追加され、mockオブジェクトが呼ばれたかどうかを確認できるようなった。
urllib.request
HTTPリクエストがファイルか繰り返し可能なボディ(ただしバイトオブジェクトを除く)を持ちながら、Content-lengthヘッダが指定されなかった場合、これまではエラーになっていたが、Chunked転送エンコーディングを行って送出するようになった。
urllib.robotparser
RobotFileParser
がCrawl-delay
拡張とRequest-rate
拡張をサポートするようになった。これらはrobots.txtでクローリング間隔の調整に使うものだ。
- Crawl-delay: クローリングを始める前に待たなければならない時間(秒)
- Request-rate: 一定時間内に要求できるページ数
warnings
warnings.warn_explicit()
関数にsource
パラメータが追加され、ResourceWarning
を発生させたオブジェクトがわかるようになった。source
属性はwarnings.WarningMessage
にも追加されている。
そして、ResourceWarningがあがる時にはtracemallocが使われ、消去対象のオブジェクトのメモリのトレースバックが取れるようになった。こんな例が挙げてある。
import warnings
def func():
return open(__file__)
f = func()
f = None
func
関数の中でファイルをオープンし、その直後にそのファイルオブジェクトへの参照をNULLで上書きすることで切ってしまっている。これを実行するとこのようになる。
$ python -Wd -X tracemalloc=5 example.py
example.py:7: ResourceWarning: unclosed file <_io.TextIOWrapper name='example.py' mode='r' encoding='UTF-8'>
f = None
Object allocated at (most recent call first):
File "example.py", lineno 4
return open(__file__)
File "example.py", lineno 6
f = func()
winreg
Windows環境のレジストリを操作するwinregモジュールで64ビット整数のREG_QWORD型がサポートされた。
winsound
Beep、MessageBeep、PlaySoundでキーワード引数を渡せるようになった。
xmlrpc.client
Apache XML-RPC実装で新たに導入された数値型とNone
の非整列化(unmarshalling)をサポート
zipfile
ZipInfo.from_file()
というクラスメソッドが追加され、ZipInfoオブジェクトをファイル名を指定して作れるようになり、ZipInfo.is_dir()
メソッドでそれがディレクトリであるかどうかを確認できるようになった。そして、ZipFile.open()
はZIPファイルからデータを取り出すだけでなく、書き込みを行うためにも使えるようになった。
zlib
compress()
関数がlevel
をキーワード引数として指定できるようになった。
fileinput
hook_encoded()
でファイルオープン時に使うエンコーディングだけでなく、エラーハンドラーも指定できるようになった。詳細はopen()
のerrors
パラメータを参照のこと。
最適化
- ASCIIデコーダは、エラーハンドラーが
surrogateescape
ignore
replace
の時に最大60倍速くなった。 - ASCIIとLatin1エンコーダは、エラーハンドラーが
surrogateescape
の時に最大3倍速くなった。 - UTF-8エンコーダは、エラーハンドラーが
ignore
replace
surrogateescape
surrogatepass
の時に最大75倍速くなった。 - UTF-8デコーダは、エラーハンドラーが
ignore
replace
surrogateescape
の時に最大15倍速くなった。 - bytes % args が最大2倍速くなった。
- bytearray % args が2.5倍から5倍速くなった。
-
bytes.fromhex()
とbytearray.fromhex()
が2倍から3.5倍速くなった。 -
bytes.replace(b'', b'.')
とbytearray.replace(b'', b'.')
が最大80%速くなった。 - PyMem_Malloc()ドメインのメモリ割り当てにCライブラリのmallocに代わってpymallocを使うようになった。pymallocは512バイト以下の短命のオブジェクト向けに最適化されていて、それよりも大きなブロックの確保にはmallocを使う。
-
pickle.load()
とpickle.loads()
は大量の小さなオブジェクトをロードする際に最大10%速くなった。 - キーワード引数は位置引数を引き渡すよりもオーバーヘッドがあるが、Argument Clinic (CPythonのCコードの為のプリプロセッサ)を使った機能により、そのオーバーヘッドは大幅に削減された。
- globモジュール中のglob()とiglob()が最適化され、3から6倍速くなった。
- os.scandir()を使ったpathlibのglobbingを最適化し、1.5から4倍速くなった
ビルドとC APIの変更
- PythonをビルドするのにC99をサポートしたツールチェーンが必要になった。
- CpythonをAndroid NDKでクロスコンパイルし、Android API レベル21以上で正常に動かすことができるようになった。Androidはまだ正式にサポートしているプラットフォームではないが、Androidエミュレータ上での標準テストスイートの実行結果は良好(16の失敗のみ)である。
- コンフィギュレーションフラグに
--with-optimization
が追加された。これを指定するとLTO(Link Time Optimization:リンク時最適化)とPGO(Profile-Guided Optimization:プロファイルに基づく最適化)ビルドサポートが有効になる。 -
Py_FinalizeEx()
APIが導入され、インタープリターの終了処理が成功したかどうか(終了処理中にエラーがあったかどうか)が判るようになった。 -
PyArg_ParseTupleAndKeywords()
が位置専用引数のサポートを行うようになった。 -
PyTrackback_Print
は長い繰り返しを省略して表示するようになった。
廃止候補
廃止予定のビルドオプション
--with-system-ffi
オプションはOSX以外のプラットフォームではデフォルトで有効になった。--without-system-ffi
で無効にすることはできるが、このフラグの使用はPython 3.7以降できなくなる。OSXはこの変更の影響を受けない。
新たなキーワード
async
とawait
を変数名、クラス名、関数名、モジュール名として使うことは非推奨となった。PEP-492によってPython3.5で導入されたasync
とawait
はPython 3.7で正式なキーワードになる予定。
廃止予定のPythonモジュール、関数、メソッド
- importlib.machinery.SourceFileLoader.load_module() importlib.machinery.SourcelessFileLoader.load_module()は廃止予定となった。
- tkinter.tixモジュールは廃止予定となった。代りにtkinter.ttkを使うべし。
廃止予定のC APIの関数および型
- (今のところなし)
廃止予定の機能
-
pyvenv
スクリプトは廃止予定。代りにpython3 -m venv
の仕様が推奨される - 相対インポートを行うときに
__spec__
あるいは__package__
が定義されていないとImportWarning例外を起きるようになった。 -
dbm.dumb
モジュールは常にアップデート可の状態でオープンされ、存在しなければ作成されていた。他のdbmの実装と合わせるためにこの動作は廃止予定とされ、Python 3.8で利用不可となる。 - 幾つかのモジュールでパスとして使われていたバイト風オブジェクトの利用は廃止予定となった。
- disutilsの
extra_path
は廃止予定となった。 - バックスラッシュと文字の組み合わせで正しいエスケープシーケンスになっていない場合にはDeprecationWarningを起こすことになった。将来的には文法エラーになるが暫くはこのまま。
- インラインフラグ
(?letters)
は正規表現の先頭でのみ使えることとなった。 - SSL関連の
certfile
、keyfile
、check_hostname
のような引数は、ftplib、http.client、imaplib、poplib、smtplibなどで使われているがそれは廃止予定となった。代りにcontext
を使うことが期待される。 - sslモジュール内の幾つかのプロトコルや関数が廃止予定となった。将来のOpenSSLでなくなるものや、他の代替手段が提供されたものなど。
廃止予定のPythonの動作
- ジェネレータ内でStopIterationをあげるとDeprecationWarningがあがる様になった。3.7からはこれがRuntimeErrorとなる。
削除済み
APIと機能の削除
-
inspect.getmoduleinfo()
は削除された。あるパスのモジュール名を知るにはinspect.getmodulename()
を使う。 -
traceback.Ignore
クラスとtraceback.usage
traceback.modname
traceback.fullmodname
traceback.find_lines_from_code
traceback.find_lines
traceback.find_strings
traceback.find_executable_lines
メソッドはtracebackモジュールから消去された。これらは3.2から廃止候補でプライベートメソッドで同様の機能は提供されている。 -
tk_menuBar()
tk_bindForTraversal()
ダミーメソッドはtkinterウィジェットクラスから消去された。 -
zipfile.ZipFile
クラスのopen()
メソッドは、'U'モードのサポートを廃止。代替としてio.TextIOWrapper
を圧縮ファイルの読み込みに使うべし。
Python 3.6へのポーティングに際して
ここでは、あなたのコードをPython3.6へポーティングする際に気をつけるべきことを列挙する。
Pythonコマンドの動作
-
COUNT_ALLOCS
SHOW_ALLOC_COUNT
SHOW_TRACK_COUNT
マクロを定義してビルドしたPythonの出力はデフォルトでオフになった。これをオンにするには-X showalloccount
を引数に追加してPythonを起動すると良い。また出力先はstdoutからstderrになった。
Python APIの変更
- (ちょっと細かいので割愛)
C APIの変更
-
PyMem_Malloc()
メモリ割り当てはシステムのmalocではなく、pymallocを使うようになったので、GILを取らずにPyMem_Malloc()
を呼ぶアプリはクラッシュするようになる。PYTHONMALLOC
環境変数をdebug
にすればメモリ割り当てが確認できる。 -
Py_Exit()
(とメインのインタープリター)は終了時のメモリ解放に失敗すると120を返すようになった。
最後に
ざっと変更点を見るつもりだったが、見ているうちに色々と興味深い点が出てきて、思ったよりも時間がかかってしまった。今現在、b1でこれ以上の変更は定義上はないので、タイトルから"(α3版)"を消した。3.6のfinalが12月中旬の予定なのでもしかするとまた変更が入るかもしれないが、適宜アップデートしていこう。