What's New In Python 3.1

著者:

Raymond Hettinger

この記事では Python 3.0 と比較した Python 3.1 の新機能を説明します。 Python 3.1 は 2009 年 6 月 27 日にリリースされました。

PEP 372: 順序付き辞書

通常の Python 辞書は、 key/value ペアを不定の順序でイテレートします。何年にもわたり、いろいろな人が key の挿入順を保存する辞書の別実装を書いてきました。その経験に基づき、新しい OrderedDict クラスが導入されました。

OrderedDict API は通常の辞書と同じインターフェースを提供していますが、 key/value をイテレートするときに key が最初に挿入された順番になることが保証されています。新しいエントリが既存のエントリを上書きした場合は、元の挿入順序が保持されます。エントリを削除して再挿入すると、順序は一番最後に移動します。

標準ライブラリのいくつかのモジュールで、順序付き辞書の利用がサポートされています。configparser モジュールはデフォルトで順序付き辞書を使います。設定ファイルを読み込み、編集した後、元の順序で書きなおすことができます。collections.namedtuple() の _asdict() メソッドは、タプルの順序と同じ順序の順序付き辞書を返すようになりました。json モジュールのデコーダーが OrderedDict をビルドするのをサポートするために、 JSONDecoder クラスのコンストラクタに object_pairs_hook 引数が追加されました。 PyYAML などの外部のライブラリでもサポートされています。

参考

PEP 372 - 順序付き辞書

PEP written by Armin Ronacher and Raymond Hettinger. Implementation written by Raymond Hettinger.

順序付き辞書は挿入順序を記憶するので、ソートと組み合わせて使うことで、ソートされた辞書を作れます:

>>> # 通常のソートされていない辞書
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # キーでソートした辞書
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # 値でソートした辞書
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # キー文字列の長さでソートした辞書
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

この新しい順序付き辞書は、項目が削除されてもソートされた順序を保持します。しかし、キーが追加されるとき、そのキーは最後に追加され、ソートは保持されません。

PEP 378: 1000区切りのための書式指定子

組み込みの format() 関数と str.format() メソッドが使うミニ言語に、単純でロケールに依存しない 1000 区切りカンマの書式化が追加されました。これによって簡単にプログラムの出力を、その玄人ちっくな見た目を改善してひとさまにとって読みやすいものに出来ます:

>>> format(1234567, ',d')
'1,234,567'
>>> format(1234567.89, ',.2f')
'1,234,567.89'
>>> format(12345.6 + 8901234.12j, ',f')
'12,345.600000+8,901,234.120000j'
>>> format(Decimal('1234567.89'), ',f')
'1,234,567.89'

これをサポートする型は int, float, complex , decimal.Decimal です。

ドットやら空白やらアポストロフィやらあるいはアンダースコアなどの他のセパレータをどうやって指定するかの議論は水面下にありますが、ロケールに従う必要があるアプリケーションは、1000区切りセパレータについていくつかのサポートを既に持っている既存の n 指定子を使うべきです。

参考

PEP 378 - 1000区切りのための書式指定子

PEP written by Raymond Hettinger and implemented by Eric Smith and Mark Dickinson.

その他の言語変更

Python 言語コアに小さな変更がいくつか行われました:

  • __main__.py を含むディレクトと zip アーカイブを、その名前をインタプリタに渡すことで直接実行出来るようになりました。そのディレクトリと zip ファイルは自動的に sys.path エントリの先頭に挿入されます。(Suggestion and initial patch by Andy Chu; revised patch by Phillip J. Eby and Nick Coghlan; bpo-1739468.)

  • int() 型に bit_length メソッドが追加されました。 このメソッドはその値を二進数で表現するのに必要なビット数を返します:

    >>> n = 37
    >>> bin(37)
    '0b100101'
    >>> n.bit_length()
    6
    >>> n = 2**123-1
    >>> n.bit_length()
    123
    >>> (n+1).bit_length()
    124
    

    (Contributed by Fredrik Johansson, Victor Stinner, Raymond Hettinger, and Mark Dickinson; bpo-3439.)

  • format() 文字列のフィールドに自動的に番号が振られるようになりました:

    >>> 'Sir {} of {}'.format('Gallahad', 'Camelot')
    'Sir Gallahad of Camelot'
    

    以前は、文字列は 'Sir {0} of {1}' のようにフィールドに番号を振らなければなりませんでした。

    (Contributed by Eric Smith; bpo-5237.)

  • string.maketrans() 関数は非推奨となり、新しい静的メソッド bytes.maketrans() と bytearray.maketrans() に置き換えられました。 この変更により、string モジュールがどの型をサポートするかという混乱が解消されます。 str、bytes、bytearray は、それぞれ適切な型の中間変換テーブルを使う独自の maketrans メソッドと translate メソッドを持つようになりました。

    (Contributed by Georg Brandl; bpo-5675.)

  • with 文のシンタックスは一つの文で複数のコンテキストマネージャを使えるようになりました:

    >>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
    ...     for line in infile:
    ...         if '<critical>' in line:
    ...             outfile.write(line)
    

    新しい構文により contextlib.nested() 関数は不要となり、非推奨になりました。

    (Georg Brandl と Mattias Brändström の貢献; appspot issue 53094.)

  • round(x, n) は x が整数の場合、整数を返すようになりました。以前は浮動小数点を返していました:

    >>> round(1123, -2)
    1100
    

    (Contributed by Mark Dickinson; bpo-4707.)

  • Python は、値を変えずに浮動小数点数を表せる最短の文字列表現を求める David Gay のアルゴリズムを使うようになりました。 これにより、二進浮動小数点数にまつわる混乱がいくらか軽減されるはずです。

    この変更の意味は、二進浮動小数点数で正確に表せない 1.1 のような数を見ると分かります。 正確に表せないため、float('1.1') のような式は表現できる最も近い値に評価されます。 その値は十六進数では 0x1.199999999999ap+0、十進数では 1.100000000000000088817841970012523233890533447265625 です。 以降の浮動小数点演算には、以前も今もこの最も近い値が使われます。

    新しくなったのは数値の表示方法です。 以前の Python は単純な方法を使っていました。 repr(1.1) の値を format(1.1, '.17g') として計算し、'1.1000000000000001' を返していました。 17 桁を使う利点は、IEEE-754 の保証に基づき、eval(repr(1.1)) が正確に元の値に戻ることを保証できる点でした。 欠点は、多くの人がこの出力に混乱したことです (二進浮動小数点表現に本来備わる制限を Python 自体の問題と誤解していました)。

    新しいアルゴリズムでは repr(1.1) はより賢明で '1.1' を返します。実際的には、これは全ての等価な文字列表現 (前提となる同じ浮動小数点数に戻るもの) を探し、そして一番短い表現を返します。

    新アルゴリズムは、可能な限りよりわかりやすい表現を生み出す傾向がありますが、元の値を変更しません。ですから 1.1 + 2.2 != 3.3 は表示がどうであれ、今でも問題です。

    新しいアルゴリズムは、基盤となる浮動小数点実装の特定の機能に依存します。 必要な機能がなければ、引き続き従来のアルゴリズムを使います。 また、テキスト形式の pickle プロトコルは、従来のアルゴリズムを使ってプラットフォーム間の移植性を保証します。

    (Contributed by Eric Smith and Mark Dickinson; bpo-1580)

新たなモジュール、改良されたモジュール、非推奨のモジュール

  • シーケンスまたはイテラブル内にある一意な要素を数え上げるのに便利な collections.Counter クラスが追加されました:

    >>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
    Counter({'blue': 3, 'red': 2, 'green': 1})
    

    (Contributed by Raymond Hettinger; bpo-1696199.)

  • Tk のテーマ付きウィジェットへのアクセスを提供する、新しい tkinter.ttk モジュールが追加されました。 tkinter.ttk の基本的なアイディアは、拡張可能性のためにウィジェットの動作を実装するコードと見た目を記述するコードを分離することです。

    (Contributed by Guilherme Polo; bpo-2983.)

  • gzip.GzipFile と bz2.BZ2File クラスはコンテキストマネジメントプロトコルをサポートするようになりました:

    >>> # 書き込み後にファイルを自動的に閉じる
    >>> with gzip.GzipFile(filename, "wb") as f:
    ...     f.write(b"xxx")
    

    (Contributed by Antoine Pitrou.)

  • decimal モジュールが二進 float から decimal オブジェクトを生成するメソッドをサポートしました。 変換は正確ですが時に意外なことがあります:

    >>> Decimal.from_float(1.1)
    Decimal('1.100000000000000088817841970012523233890533447265625')
    

    長い十進の結果が、 1.1 を記憶するための現実の二進での端数を表しています。 1.1 は二進数で正確に表現出来ないので、端数は十進表現でとても多くの桁数になっています。

    (Contributed by Raymond Hettinger and Mark Dickinson.)

  • itertools に 2 つの関数が追加されました。 itertools.combinations_with_replacement() 関数は、置換 (順列, permutation) や直積 (Cartesian product) を含む組合せ論の 4 つの生成関数のうちの 1 つです。 itertools.compress() 関数は APL の同名機能の模倣品です。また、既存の itertools.count() 関数は新たにオプショナルな step 引数を取るようになり、そして数え方に fractions.Fraction や decimal.Decimal を含む任意の数値型を使えるようになりました。

    >>> [p+q for p,q in combinations_with_replacement('LOVE', 2)]
    ['LL', 'LO', 'LV', 'LE', 'OO', 'OV', 'OE', 'VV', 'VE', 'EE']
    
    >>> list(compress(data=range(10), selectors=[0,0,1,1,0,1,0,1,0,0]))
    [2, 3, 5, 7]
    
    >>> c = count(start=Fraction(1,2), step=Fraction(1,6))
    >>> [next(c), next(c), next(c), next(c)]
    [Fraction(1, 2), Fraction(2, 3), Fraction(5, 6), Fraction(1, 1)]
    

    (Contributed by Raymond Hettinger.)

  • collections.namedtuple() が新たにキーワード引数 rename をサポートし、これにより不正なフィールド名を自動で _0, _1, ... といった位置による名前に変換することが出来ます。これはフィールド名が何か外部ソースに基いて作られる場合に有用です。例えば CSV のヘッダ、SQL のフィールドリスト、あるいはユーザ入力などです:

    >>> query = input()
    SELECT region, dept, count(*) FROM main GROUPBY region, dept
    
    >>> cursor.execute(query)
    >>> query_fields = [desc[0] for desc in cursor.description]
    >>> UserQuery = namedtuple('UserQuery', query_fields, rename=True)
    >>> pprint.pprint([UserQuery(*row) for row in cursor])
    [UserQuery(region='South', dept='Shipping', _2=185),
     UserQuery(region='North', dept='Accounting', _2=37),
     UserQuery(region='West', dept='Sales', _2=419)]
    

    (Contributed by Raymond Hettinger; bpo-1818.)

  • re.sub()、re.subn() および re.split() 関数は flags 引数を受け取るようになりました。

    (Contributed by Gregory Smith.)

  • logging を自身では使わずとも使用ライブラリがそうしているようなアプリケーションのために、 logging モジュールが単純な logging.NullHandler を実装しました。null ハンドラをセットアップすることは、 "No handlers could be found for logger foo" のような警告を抑制します。

    >>> h = logging.NullHandler()
    >>> logging.getLogger("foo").addHandler(h)
    

    (Contributed by Vinay Sajip; bpo-4384).

  • コマンドラインスイッチ -m をサポートしている runpy がパッケージの実行をサポートするようになりました。パッケージ名が与えられると __main__ サブモジュールを探し出して実行します。

    (Contributed by Andi Vajda; bpo-4195.)

  • pdb モジュールが zipimport (あるいはなにかほかの PEP 302 準拠ローダ) でロードされたモジュールのソースコードにアクセスでき、表示できるようになりました。

    (Contributed by Alexander Belopolsky; bpo-4201.)

  • functools.partial オブジェクトが pickle 化出来るようになりました。

(Suggested by Antoine Pitrou and Jesse Noller. Implemented by Jack Diederich; bpo-5228.)

  • シンボルのための pydoc ヘルプトピックが追加されました。これで対話環境で help('@') などが期待通りの働きをします (---訳注: 実装としては pydoc_data パッケージのこと。 pydoc_data/topics.py に docstring からは生成出来ない、シンボルについてのドキュメントが収められています ---)。

    (Contributed by David Laban; bpo-4739.)

  • unittest に特定のテストメソッドやテストクラス全体をスキップする仕組みのサポートが追加されました。さらに、この機能はテスト結果を「意図的な失敗」とすることができ、テストが失敗しても TestResult の失敗数にはカウントされなくなります:

    class TestGizmo(unittest.TestCase):
    
        @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
        def test_gizmo_on_windows(self):
            ...
    
        @unittest.expectedFailure
        def test_gimzo_without_required_library(self):
            ...
    

    また例外についてのテストが、 with 文で使えるコンテキストマネージャとして増強されました:

    def test_division_by_zero(self):
        with self.assertRaises(ZeroDivisionError):
            x / 0
    

    さらに、assertSetEqual()、assertDictEqual()、assertDictContainsSubset()、assertListEqual()、assertTupleEqual()、assertSequenceEqual()、assertRaisesRegexp()、assertIsNone()、assertIsNotNone() など、新しいアサーションメソッドが追加されました。

    (Contributed by Benjamin Peterson and Antoine Pitrou.)

  • io モジュールに seek() メソッド用の三つの定数 SEEK_SET、SEEK_CUR、SEEK_END が追加されました。

  • sys.version_info タプルが名前付きタプルになりました。

    >>> sys.version_info
    sys.version_info(major=3, minor=1, micro=0, releaselevel='alpha', serial=2)
    

    (Contributed by Ross Light; bpo-4285.)

  • nntplib モジュールと imaplib モジュールが IPv6 をサポートするようになりました。

    (Contributed by Derek Morr; bpo-1655 and bpo-1664.)

  • pickle を、プロトコル 2 以下を使う際に Python 2.x との相互運用に順応するようにしました。標準ライブラリの再編成はたくさんのオブジェクトへの公式な参照を変えました。例えば Python 2 の __builtin__.set は Python 3 では builtins.set です。この変化は異なる Python バージョン間でのデータ共有の取り組みを複雑にしました。ですが今回のこの修正により、プロトコル 2 以下を選んだ場合は pickler は自動的にロード時もダンプ時も古い Python 2 命名を使うようになります。この再マッピングはデフォルトで有効になりますが、 fix_imports オプションで無効に出来ます:

    >>> s = {1, 2, 3}
    >>> pickle.dumps(s, protocol=0)
    b'c__builtin__\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
    >>> pickle.dumps(s, protocol=0, fix_imports=False)
    b'cbuiltins\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
    

    不幸にも、そして避けられないこの変更による副作用は、Python 3.1 によって生成されたプロトコル 2 pickle が Python 3.0 で読めなくなるであろうことです。Python 2.x との互換性を維持するつもりがないのであれば、Python 3.x 実装間でのデータ移行では最新 pickle プロトコルバージョン 3 を使うべきです。

    (Contributed by Alexandre Vassalotti and Antoine Pitrou, bpo-6137.)

  • 新規モジュール importlib が追加されました。 import 文とその相棒の __import__() 関数の、完全で移植性が高いピュア Python 参照実装を提供しています。これはインポートで行う動作の文書化と定義における、確かな前進です。

    (Contributed by Brett Cannon.)

最適化

大きな性能向上がありました:

  • PEP 3116 で定義された新しい I/O ライブラリは、その大半が Python で書かれており、Python 3.0 では早くから性能のボトルネックになると分かりました。 Python 3.1 では I/O ライブラリ全体が C で書き直され、処理の内容に応じて 2〜20 倍高速になりました。 実験用に、Python だけで書かれたバージョンも _pyio モジュールとして引き続き利用できます。

    (Contributed by Amaury Forgeot d'Arc and Antoine Pitrou.)

  • 追跡対象外のオブジェクトだけを含むタプルと辞書を、ガベージコレクタの追跡対象から外す判定を追加しました。 これにより、長時間実行するプログラムではデータ型の使い方に応じて回収対象を減らし、ガベージコレクションのオーバーヘッドを抑えられます。

    (Contributed by Antoine Pitrou, bpo-4688.)

  • 対応するコンパイラ (特に gcc、SunPro、icc) で configure オプション --with-computed-gotos を有効にすると、バイトコード評価ループが新しいディスパッチ方式でコンパイルされます。 システム、コンパイラ、ベンチマークに応じて最大 20% 高速になります。

    (Contributed by Antoine Pitrou along with a number of other participants, bpo-4753).

  • UTF-8, UTF-16 ならびに LATIN-1 のデコーディングが2から4倍速くなりました。

    (Antoine Pitrou と Amaury Forgeot d'Arc の貢献, bpo-4868.)

  • json モジュールに C 拡張が追加され、性能が大幅に改善されました。 また、API が変更され、json は bytes ではなく str だけを扱うようになりました。 これにより、Unicode を前提として定義されている JSON 仕様 により忠実なモジュールになりました。

    (Contributed by Bob Ippolito and converted to Py3.1 by Antoine Pitrou and Benjamin Peterson; bpo-4136.)

  • unpickle 時に、pickle されたオブジェクトの属性名をインターン化するようになりました。 これによりメモリを節約し、pickle を小さくできます。

    (Contributed by Jake McGuire and Antoine Pitrou; bpo-5084.)

IDLE

  • IDLE のフォーマットメニューに、ソースコードから末尾の空白を取り除くことが出来るオプションが追加されました。

    (Contributed by Roger D. Serwy; bpo-5150.)

ビルドならびに C API の変更

Python のビルド過程と C API の変更は以下の通りです:

  • 整数の内部格納方式が 2**15 ベースと 2**30 ベースのいずれかになりました。 これはビルド時に決定されます。 以前は常に 2**15 ベースで格納されていました。 2**30 ベースにすると 64 bit マシンでは性能が有意に向上しますが、 32 bit マシンでのベンチマーク結果には向上も低下もあります。 そのため、デフォルトでは 64 bit マシンで 2**30 ベースを、 32 bit マシンで 2**15 ベースを使用します。 Unix では新たな configure オプション --enable-big-digits が追加されました。 これにより上記のデフォルトを上書き出来ます。

    この変更は性能向上以外ではエンドユーザには分からないはずですが、例外が1つあります。 テストおよびデバッグ目的で内部形式の情報を提供する sys.int_info が追加されましたが、これにより数字あたりのビット数と各数字の格納に使われる C の型のバイトサイズが分かります:

    >>> import sys
    >>> sys.int_info
    sys.int_info(bits_per_digit=30, sizeof_digit=4)
    

    (Contributed by Mark Dickinson; bpo-4258.)

  • PyLong_AsUnsignedLongLong() 関数は負の pylong に対し TypeError ではなく OverflowError を送出するようになりました。

    (Contributed by Mark Dickinson and Lisandro Dalcrin; bpo-5175.)

  • PyNumber_Int() が非推奨になりました。代わりに PyNumber_Long() を使用してください。

    (Contributed by Mark Dickinson; bpo-4910.)

  • 非推奨の関数 PyOS_ascii_strtod() および PyOS_ascii_atof() を置き換えるために新しく PyOS_string_to_double() 関数が追加されました。

    (Contributed by Mark Dickinson; bpo-5914.)

  • PyCObject API を置き換えるものとして、 PyCapsule が追加されました。主な違いとしては、新しい型は、型安全に情報を渡すための良く定義されたインターフェースを持ち、また、デストラクタの呼び出しのシグネチャの複雑さが小さくなっています。古い型は問題のある API で、今では非推奨です。

    (Contributed by Larry Hastings; bpo-5630.)

Python 3.1 への移植

このセクションでは前述の変更とバグフィックスにより必要となるかもしれないコードの変更を列挙します:

  • 浮動小数点数の新しい文字列表現により、既存の doctest が失敗することがあります。 例えば次のようになります。

    def e():
        '''自然対数の底を計算します。
    
        >>> e()
        2.7182818284590451
    
        '''
        return sum(1/math.factorial(x) for x in reversed(range(30)))
    
    doctest.testmod()
    
    **********************************************************************
    Failed example:
        e()
    Expected:
        2.7182818284590451
    Got:
        2.718281828459045
    **********************************************************************
    
  • pickle モジュールがプロトコルバージョン 2 以下で自動的に名前の再対応付けを行うので、Python 3.1 で pickle 化すると Python 3.0 で読めなくなります。一つの解決策はプロトコル 3 を使うことです。もう一つは fix_imports オプションを False にセットすることです。上述の議論を参照してください。