What's New In Python 3.1

著者:

Raymond Hettinger

この記事では 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.

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

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> 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.)

  • The string.maketrans() function is deprecated and is replaced by new static methods, bytes.maketrans() and bytearray.maketrans(). This change solves the confusion around which types were supported by the string module. Now, str, bytes, and bytearray each have their own maketrans and translate methods with intermediate translation tables of the appropriate type.

    (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)
    

    With the new syntax, the contextlib.nested() function is no longer needed and is now deprecated.

    (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.GzipFilebz2.BZ2File クラスはコンテキストマネジメントプロトコルをサポートするようになりました:

    >>> # Automatically close file after writing
    >>> 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.Fractiondecimal.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
    

    In addition, several new assertion methods were added including assertSetEqual(), assertDictEqual(), assertDictContainsSubset(), assertListEqual(), assertTupleEqual(), assertSequenceEqual(), assertRaisesRegexp(), assertIsNone(), and assertIsNotNone().

    (Contributed by Benjamin Peterson and Antoine Pitrou.)

  • The io module has three new constants for the seek() method: SEEK_SET, SEEK_CUR, and 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.)

最適化

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

  • The new I/O library (as defined in PEP 3116) was mostly written in Python and quickly proved to be a problematic bottleneck in Python 3.0. In Python 3.1, the I/O library has been entirely rewritten in C and is 2 to 20 times faster depending on the task at hand. The pure Python version is still available for experimentation purposes through the _pyio module.

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

  • Added a heuristic so that tuples and dicts containing only untrackable objects are not tracked by the garbage collector. This can reduce the size of collections and therefore the garbage collection overhead on long-running programs, depending on their particular use of datatypes.

    (Contributed by Antoine Pitrou, bpo-4688.)

  • Enabling a configure option named --with-computed-gotos on compilers that support it (notably: gcc, SunPro, icc), the bytecode evaluation loop is compiled with a new dispatch mechanism which gives speedups of up to 20%, depending on the system, the compiler, and the benchmark.

    (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.)

  • The json module now has a C extension to substantially improve its performance. In addition, the API was modified so that json works only with str, not with bytes. That change makes the module closely match the JSON specification which is defined in terms of Unicode.

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

  • Unpickling now interns the attribute names of pickled objects. This saves memory and allows pickles to be smaller.

    (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():
        '''Compute the base of natural logarithms.
    
        >>> 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 にセットすることです。上述の議論を参照してください。