What's New in Python 2.4

著者:

A.M. Kuchling

この文書は 2005 年 3 月 30 日にリリースされた Python 2.4.1 の新機能について解説します。

Python 2.4 は、真ん中サイズ、のリリースです。急進的だった Python 2.2 ほどには多くの変更をしていませんが、保守的だった 2.3 よりは多くの機能を導入しています。新しい言語機能で最も重要なのが、関数デコレータとジェネレータ式です。ほかのほとんどの変更は標準ライブラリに対するものです。

Python 2.3 から 2.4 の CVS 変更ログによれば、適用されたパッチは 481、フィックスされたバグは 502 ありました。ともに、少なく見積もって、です。

このドキュメントは個々の新機能の完全な詳細を提供するのではなくて、簡易な概要を提供することを目的にしています。完全な詳細が知りたければ、 Python ライブラリリファレンス、Python リファレンスマニュアルのような Python 2.4 のドキュメントを参照してください。多くの場合個別の新機能についての実装の説明やデザインの根拠については PEP に託されています。

PEP 218: ビルトインの集合オブジェクト

Python 2.3 では sets モジュールが導入されました。 集合データ型の C 実装が、新しい 2 つの組み込み型 set(iterable) と frozenset(iterable) として Python のコアに加わりました。 要素の所属判定、シーケンスからの重複の除去、和集合・共通部分・差集合・対称差といった数学的な操作を高速に行えます。

>>> a = set('abracadabra')              # 文字列から集合を作る
>>> 'z' in a                            # 高速な所属判定
False
>>> a                                   # a に含まれる重複しない文字
set(['a', 'r', 'b', 'c', 'd'])
>>> ''.join(a)                          # 文字列に戻す
'arbcd'

>>> b = set('alacazam')                 # 2 つ目の集合を作る
>>> a - b                               # a に含まれ b に含まれない文字
set(['r', 'd', 'b'])
>>> a | b                               # a または b に含まれる文字
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b                               # a と b の両方に含まれる文字
set(['a', 'c'])
>>> a ^ b                               # a または b の片方だけに含まれる文字
set(['r', 'd', 'b', 'm', 'z', 'l'])

>>> a.add('z')                          # 新しい要素を追加
>>> a.update('wxy')                     # 複数の新しい要素を追加
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
>>> a.remove('x')                       # 要素を一つ取り除く
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])

frozenset() 型は set() の immutable 版です。 immutable かつハッシュ可能なので、辞書のキーやほかの set のメンバとして使えるでしょう。

sets モジュールも標準ライブラリに残っており、Set や ImmutableSet のサブクラスを作りたい場合に役立つかもしれません。 現時点でこのモジュールを非推奨にする予定はありません。

参考

PEP 218 - 集合オブジェクト型をビルトインに追加する

元々は Greg Wilson によって提案され、完全な実装は Raymond Hettinger によってなされました。

PEP 237: 長整数と整数を一体化していく

この PEP の非常に長期に渡る移行は Python 2.2 に始まり、Python 2.4 でさらにもう一歩前進しています。2.3 では int/long の一体化後に異なる振る舞いをする整数演算をすると FutureWarning 警告を出して、結果の値は (プラットフォーム依存で) 32 ビットまたは 64 ビットに制限していました。2.4 ではこれらの式はもう警告は出さず、代わりにいつでも(2.3 とは違った)長整数となる結果をはじき出します。

問題を起こしうる式は主として左シフトで、そして長い 16 進リテラルと 8 進リテラルです。例えば 2 << 32 は 2.3 では警告とともに 32 ビットプラットフォームでは結果は 0 になります。Python 2.4 ではこの式は正しい答えの 8589934592 になります。

参考

PEP 237 - 長整数と整数を一体化していく

オリジナルの PEP は Moshe Zadka と GvR (Guido van Rossum) によって書かれました。.2.4 での変更については Kalle Svensson によって実装されました。

PEP 289: ジェネレータ式

Python 2.2 で導入されたイテレータ機能と itertools モジュールによって、データセット全体を一度にメモリへ読み込まずに、大きなデータセットをループで処理するプログラムが書きやすくなりました。 リスト内包表記はすべての要素を含む Python のリストオブジェクトを作るので、この用途にはあまり向きません。 必然的にすべてのオブジェクトをメモリへ読み込むことになり、データセットが非常に大きい場合には問題になり得ます。 関数型のスタイルでプログラムを書こうとすると、次のように書くのが自然でしょう。

links = [link for link in get_all_links() if not link.followed]
for link in links:
    ...

こうではなく

for link in get_all_links():
    if link.followed:
        continue
    ...

最初の形の方が簡潔でおそらく読みやすいですが、扱っているのがとても多くのリンクオブジェクトであるならば、全てのリンクオブジェクトが一気にメモリに載らないように二つ目の形で書く必要がありました。

ジェネレータ式はリスト内包と似た動作をしますが、リスト全体を実体化しません; 代わりにそれは、要素を一つずつ返すジェネレータを返します。上述の例はこう書けます:

links = (link for link in get_all_links() if not link.followed)
for link in links:
    ...

上の例でのように、ジェネレータ式は常に括弧の中に書かなければなりません。関数呼び出しを囲む括弧もそれに含まれるので、関数にそのまま渡すイテレータを作りたければこれで良いです:

print sum(obj.count for obj in list_all_objects())

ジェネレータ式はリスト内包とは色々小さい点で違います。最も顕著なのはループ変数 (上の例での obj) がジェネレータ式の外からアクセス不能なことです。リスト内包はループの制御変数が最後に代入された値で残ります; 将来のバージョンの Python では、この振る舞いはリスト内包がこの点でジェネレータ式と同じになるように変更されます。 (---訳注: Python 2.7 でもリスト内包のこの振る舞いは変わっておらず、警告ともなりません。制御変数が内包のスコープ外で可視でなくなったのは Python 3.0 からです。---)

参考

PEP 289 - ジェネレータ式

Raymond Hettinger によって提案され、Hye-Shik Chang に導かれた早期の尽力によって Jiwon Seo により実装されました。

PEP 292: より単純な文字列置換 (string substitution)

標準ライブラリに、文字列を変数で置換するための代替メカニズムをもたらす新しいくつかのクラスが追加されました; この置換のスタイルは、訓練されていないユーザがテンプレートを編集する必要があるようなアプリケーションにとって、より良いものでしょう。

変数置換を名前で行うためのいつもの方法は % 演算子です:

>>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'}
'2: The Best of Times'

テンプレート文字列を書くのに、閉じ括弧のあとの i や s を忘れやすいです。これはそのテンプレートが Python モジュール内にあるなら大問題でもありません。コードを実行し、「サポートされないフォーマット文字 (unsupported format character)」な ValueError を喰らい、問題を直すだけのことです。ですが、例えば Mailman のようなアプリケーションを考えてみてください。テンプレート文字列や翻訳は、Python 言語について承知していないユーザが編集するのです。フォーマット文字列の構文はそのようなユーザに説明するには複雑で、彼らが間違いをやらかした場合には、親切なフィードバックを彼らに与えるのは難しいのです。

PEP 292 では、置換を示すのに $ を使う Template クラスが string モジュールに追加されます。

>>> import string
>>> t = string.Template('$page: $title')
>>> t.substitute({'page':2, 'title': 'The Best of Times'})
'2: The Best of Times'

辞書にキーがなければ、substitute() メソッドは KeyError を送出します。 存在しないキーを無視する safe_substitute() メソッドもあります。

>>> t = string.Template('$page: $title')
>>> t.safe_substitute({'page':3})
'3: $title'

参考

PEP 292 - より単純な文字列置換 (string substitution)

Barry Warsaw 著、実装

PEP 318: 関数とメソッドのためのデコレータ

Python 2.2 は Python オブジェクトモデルを静的メソッド、クラスメソッドを追加することで拡張はしましたが、それらを定義する新たな手段を提供するような Python 構文の拡張はしませんでした。このため、 def でメソッドは普通に書いたのち、新型メソッドとしての関数へ仕立て上げる staticmethod() または classmethod() にその結果のメソッドを渡す、という手順を取る必要がありました。このような具合でした:

class C:
   def meth (cls):
       ...

   meth = classmethod(meth)   # ラップしたクラスメソッドに名前を束縛し直す

メソッドがとても長かったりすると、関数のボディの後ろの classmethod() 呼び出しは見失ったり忘れたりしやすいものでした。

そのような定義をもっと読みやすくするために何か構文を追加する、という意図は常にありましたが、2.2 のリリース時点では良い構文は明らかではありませんでした。本日時点でさえ いまだ 明らかとは言えませんが、ユーザは静的メソッドとクラスメソッドを簡単に手にする手段を注文し続けています; 新たな構文的機能はこの要求に合うように追加されました。

この新たな機能は「関数デコレータ (function decorators)」と呼ばれます。この名前は classmethod(), staticmethod(), とその仲間たちが関数オブジェクトに追加的な情報を保存することから着想を得たものです; それらは関数をより多くの詳細で デコレート (修飾) している というわけです。

記法は Java より拝借して '@' 文字を指示子として使います。この新たな構文を使うと、上記の例はこのように書けます:

class C:

   @classmethod
   def meth (cls):
       ...

@classmethod は meth=classmethod(meth) 代入の速記法です。より一般的には、このように書けば…:

@A
@B
@C
def f ():
    ...

これはデコレータ前史の以下コードと等価です:

def f(): ...
f = A(B(C(f)))

デコレータは関数定義の前になければなりません。一行ごとに一つのデコレータです。 def ステートメントと同じ行にあってはダメです。つまり @A def f(): ... は不正です。モジュールレベルかクラス内の関数定義のみをデコレート出来ます; クラス定義はデコレート出来ません。(--- 訳注: クラス定義のデコレータは Python 2.6 で追加されました (PEP 3129) 。---)

デコレータはただの関数です。引数としてデコレートされる関数を取り、同じ関数か何か新しいオブジェクトを返すだけの。結果がほかのデコレータ適用されるの出ない限りは、デコレータの戻り値は呼び出し可能である必要はありません (普通はそうですが)。あなた自身のデコレータを書くのは簡単です。続く単純な例は、関数オブジェクトに単に属性をセットするだけのものです:

>>> def deco(func):
...    func.attr = 'decorated'
...    return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'
>>>

もう少しだけ現実的な例として、続く例ではデコレータに、与えられた引数が整数かどうかチェックさせてみます:

def require_int (func):
    def wrapper (arg):
        assert isinstance(arg, int)
        return func(arg)

    return wrapper

@require_int
def p1 (arg):
    print arg

@require_int
def p2(arg):
    print arg*2

PEP 318 にある例はこのアイディアのもっと凝った版が含まれていて、それは要求型の指定と戻り値のチェックの両方が出来ます。

デコレータ関数は引数を取ることが出来ます。引数が与えられた場合、あなたのデコレータ関数はそれら引数のみで呼び出され、そして新しいデコレータを返さなければなりません; この関数は単一の関数を取らなければならず、前述のように関数を返さなければなりません。言い換えると、 @A @B @C(args) はこうなります:

def f(): ...
_deco = C(args)
f = A(B(_deco(f)))

これが正しいと理解するには少しばかり頭をひねる必要がありますが、難しすぎることはありません。

関連する小さな変更として、関数の func_name 属性が書き換え可能になりました。 この属性はトレースバックで関数名を表示するために使われるので、デコレーターで新しい関数を作って返す場合は、その名前を変更するようにしてください。

参考

PEP 318 - 関数、メソッド、クラスのためのデコレータ

Kevin D. Smith, Jim Jewett, Skip Montanaro により著されました。数多くの人々が関数デコレータ実装のパッチを書きましたが、実際にチェックインされたものは Mark Russell が書いた #979728 でした。

https://wiki.python.org/moin/PythonDecoratorLibrary

数多くのデコレータ例を含む Wiki ページ。

PEP 322: 逆順のイテレーション

新しいビルトイン関数 reversed(seq) は、シーケンスを受け取って、シーケンスの要素を逆順にループするイテレータを返します:

>>> for i in reversed(xrange(1,4)):
...    print i
...
3
2
1

range(1,4)[::-1] のようにする拡張スライスでのやり方に比較して reversed() は読みやすく、実行が高速で、大体の場合はメモリ使用が少なく済みます。

reversed() は任意のイテレータは受け付けず、シーケンスのみ受け付けることに注意してください。イテレータを逆順にしたければ、最初に list() でリストに変換してください:

>>> input = open('/etc/passwd', 'r')
>>> for line in reversed(list(input)):
...   print line
...
root:*:0:0:System Administrator:/var/root:/bin/tcsh
  ...

参考

PEP 322 - 逆順のイテレーション

Raymond Hettinger 著、実装.

PEP 324: 新しい subprocess モジュール

標準ライブラリにはサブプロセスを実行する方法がいくつもあり、機能や複雑さもそれぞれ異なります。 os.system(command) は使いやすいものの、遅く (シェルのプロセスを起動してコマンドを実行します)、危険でもあります (シェルのメタ文字のエスケープに注意する必要があります)。 popen2 モジュールにはサブプロセスの標準出力や標準エラーを取得できるクラスがありますが、名前が分かりにくくなっています。 subprocess モジュールはこれを整理し、必要になり得る機能をすべて備えた統一的なインターフェースを提供します。

popen2 に複数のクラスがあるのに対し、subprocess には subprocess.Popen という一つのクラスがあり、そのコンストラクターがさまざまなキーワード引数を受け付けます。

class Popen(args, bufsize=0, executable=None,
            stdin=None, stdout=None, stderr=None,
            preexec_fn=None, close_fds=False, shell=False,
            cwd=None, env=None, universal_newlines=False,
            startupinfo=None, creationflags=0):

args は普通は文字列のシーケンスで、サブプロセスとして実行するプログラムへの引数群となります。 (shell 引数が真の場合は args はシェルに解釈を任せるために渡す文字列に出来、つまりこの場合 os.system() と同じことをします。)

stdin, stdout, stderr はサブプロセスの入力・出力・エラーのストリームを指定します。ファイルオブジェクトかファイル記述子を渡すことが出来ます。あるいは定数 subprocess.PIPE を渡してサブプロセスと親とのパイプを作成することが出来ます。

コンストラクタには多くの便利なオプションがあります:

  • close_fds はサブプロセス実行前に全てのファイル記述子をクローズすることを要求します。

  • cwd はサブプロセスを実行する作業ディレクトリを指定します (デフォルトは親の作業ディレクトリです)。

  • env は環境変数を指定する辞書です。

  • preexec_fn は子が開始する前に呼び出される関数です。

  • universal_newlines で、子の入出力を、Python の universal newlines 機能で開きます。

Popen インスタンスを作ったら、wait() メソッドでサブプロセスの終了を待つことや、poll() で待たずに終了したかどうかを確認することができます。 また communicate(data) で文字列 data をサブプロセスの標準入力へ送れます。 communicate(data) はその後、サブプロセスが標準出力や標準エラーへ送ったデータを読み取り、タプル (stdout_data, stderr_data) を返します。

call() は、引数を Popen のコンストラクターへ渡し、コマンドの終了を待ってサブプロセスのステータスコードを返す簡便な関数です。 os.system() のより安全な代わりとして使えます。

sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
if sts == 0:
    # 成功
    ...
else:
    # dpkg がエラーを返した
    ...

コマンドはシェルを使うことなく呼び出されます。もしシェルを本当に使いたいのであればキーワード引数として shell=True を与えた上でシーケンスの代わりに文字列を与えることが出来ます:

sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True)

PEP にはシェルと Python コードの様々な例が採られていて、シェルスクリプトをいかにして subprocess を用いて Python コードに変換するかを示しています。PEP のこのセクションを読むことを強くお勧めします。

参考

PEP 324 - subprocess - プロセスのための新たなモジュール

Fredrik Lundh 他によるサポートによって、Peter Åstrand により PEP 著と実装が行われました。

PEP 327: Decimal データ型

Python は当初から、基盤となる C の double 型を使った浮動小数点数 (FP) をデータ型としてサポートしてきました。 しかし、ほとんどのプログラミング言語に浮動小数点数型がある一方、多くの人 (プログラマーも含みます) は、浮動小数点数では正確に表せない有限の十進小数があることを知りません。 新しい Decimal 型は、ユーザーが指定した精度の範囲で、これらの小数を正確に表せます。

なぜ Decimal が必要なのか?

浮動小数点数が使う表現方法に起因する制約があります。浮動小数点数は 3 つの構成要素から成ります:

  • 符号(sign)。正または負。

  • 仮数部(mantissa)。一桁の 2 進値に端数部が続きます。例えば 2 進数で 1.01 は 1 + 0/2 + 1/4 で 10 進表記で 1.25 です。

  • 指数部(exponent)。小数点がその数値のどこに位置するかを表します。

例えば 1.25 は、正の符号を持ち、仮数部の値は (2 進数で) 1.01 で、指数部は 0 です (小数点は移動の必要がありません)。5 は同じ符号と仮数部を持ち、指数部は、仮数部が 4 倍なので 2 (2 を底とする 2 の 冪乗) です; 1.25 * 4 は 5 です。

Modern systems usually provide floating-point support that conforms to a standard called IEEE 754. C's double type is usually implemented as a 64-bit IEEE 754 number, which uses 52 bits of space for the mantissa. This means that numbers can only be specified to 52 bits of precision. If you're trying to represent numbers whose expansion repeats endlessly, the expansion is cut off after 52 bits. Unfortunately, most software needs to produce output in base 10, and common fractions in base 10 are often repeating decimals in binary. For example, 1.1 decimal is binary 1.0001100110011 ...; .1 = 1/16 + 1/32 + 1/256 plus an infinite number of additional terms. IEEE 754 has to chop off that infinitely repeated decimal after 52 digits, so the representation is slightly inaccurate.

ときどきあなたはこの不正確さを、数値を表示する際に目にするでしょう:

>>> 1.1
1.1000000000000001

この不正確さは数値を表示する際にいつでも目に見えるわけではありません。浮動小数点数から文字列への変換が C ライブラリによって提供されていて、C ライブラリのほとんどが賢明な出力を生成しようと頑張っているからです。それが表示されないにしても、不正確さはそれでも存在していて、後続の計算への誤差が大きくなりえます。

多くのアプリケーションではこれは重要ではありません。モニタにプロットして表示するのに 1.1 と 1.1000000000000001 の差は小さすぎて見えません。大抵は出力を一定の桁位置までに制限して出力するものですし、2 やら 3 やら 8 桁などの位置で丸めたりすれば誤差は決して露わにはなりません。ですがそれが重要なアプリケーションにとっては、あなた自身のカスタム数学ルーチンのための実装作業は膨大になります。

そこで Decimal 型が作られました。

Decimal 型

Python の標準ライブラリに、新しい decimal モジュールが加わりました。 このモジュールには Decimal と Context の 2 つのクラスがあります。 Decimal のインスタンスは数を表し、Context のインスタンスは精度やデフォルトの丸めモードなど、さまざまな設定をまとめて保持します。

Decimal のインスタンスは、通常の Python の整数や浮動小数点数と同様にイミュータブルです。 作成後に、そのインスタンスが表す値は変更できません。 Decimal のインスタンスは整数や文字列から作れます。

>>> import decimal
>>> decimal.Decimal(1972)
Decimal("1972")
>>> decimal.Decimal("1.1")
Decimal("1.1")

符号(sign)、10進数値のタプルで表した仮数部(mantissa)、指数部(exponent)を含んだタプルを渡すことも出来ます:

>>> decimal.Decimal((1, (1, 4, 7, 5), -2))
Decimal("-14.75")

注意: 符号ビットは負符号の有無なので、 0 が正、1 が負です。

浮動小数点数からの変換には、少し問題があります。 1.1 を表す浮動小数点数は、正確な 1.1 という十進数へ変換するべきでしょうか、それとも 1.1 に誤差を加えた値へ変換するべきでしょうか。 この問題を避けるため、そのような変換を API に含めないことになりました。 代わりに、浮動小数点数を必要な精度の文字列へ変換し、その文字列を Decimal のコンストラクターへ渡してください。

>>> f = 1.1
>>> decimal.Decimal(str(f))
Decimal("1.1")
>>> decimal.Decimal('%.12f' % f)
Decimal("1.100000000000")

Decimal のインスタンスができれば、通常の数学的演算を行えます。 ただし、べき乗の指数は整数に限られます。

>>> a = decimal.Decimal('35.72')
>>> b = decimal.Decimal('1.73')
>>> a+b
Decimal("37.45")
>>> a-b
Decimal("33.99")
>>> a*b
Decimal("61.7956")
>>> a/b
Decimal("20.64739884393063583815028902")
>>> a ** 2
Decimal("1275.9184")
>>> a**b
Traceback (most recent call last):
  ...
decimal.InvalidOperation: x ** (non-integer)

Decimal のインスタンスは整数と組み合わせられますが、浮動小数点数とは組み合わせられません。

>>> a + 4
Decimal("39.72")
>>> a + 4.5
Traceback (most recent call last):
  ...
TypeError: You can interact Decimal only with int, long or Decimal data types.
>>>

Decimal の数は math や cmath モジュールでも使えますが、演算の直前に浮動小数点数へ変換されるため、精度や正確さが失われる可能性があります。 返される値も Decimal ではなく、通常の浮動小数点数です。

>>> import math, cmath
>>> d = decimal.Decimal('123456789012.345')
>>> math.sqrt(d)
351364.18288201344
>>> cmath.sqrt(-d)
351364.18288201344j

Decimal のインスタンスには、Decimal を返す sqrt() メソッドがありますが、三角関数などが必要な場合は自分で実装する必要があります。

>>> d.sqrt()
Decimal("351364.1828820134592177245001")

Context 型

Context クラスのインスタンスは、十進数の演算に関するいくつかの設定をまとめて保持します。

  • prec is the precision, the number of decimal places.

  • rounding は丸めモードを指定します。 decimal モジュールには、ROUND_DOWN、ROUND_CEILING、ROUND_HALF_EVEN など、各種モードを表す定数があります。

  • traps は、特定のエラー条件が生じたときに、例外を送出するか値を返すかを指定する辞書です。 エラー条件の例としては、ゼロ除算、精度の喪失、オーバーフローがあります。

getcontext() を呼び出すと、スレッドローカルなデフォルトのコンテキストを取得できます。 このコンテキストのプロパティを変更すると、デフォルトの精度、丸め、トラップの扱いを変えられます。 次の例は、デフォルトのコンテキストの精度を変更したときの影響を示しています。

>>> decimal.getcontext().prec
28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.1428571428571428571428571429")
>>> decimal.getcontext().prec = 9
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.142857143")

エラー状態の場合のデフォルトアクションを選択出来ます; モジュールは無限大(infinity)あるいは非数(not-a-number: NaN)を返すか、例外を投げるかです:

>>> decimal.Decimal(1) / decimal.Decimal(0)
Traceback (most recent call last):
  ...
decimal.DivisionByZero: x / 0
>>> decimal.getcontext().traps[decimal.DivisionByZero] = False
>>> decimal.Decimal(1) / decimal.Decimal(0)
Decimal("Infinity")
>>>

Context インスタンスには、to_eng_string() や to_sci_string() など、数値を書式化するさまざまなメソッドもあります。

さらに詳しく知りたければ decimal モジュールのドキュメントを読んで下さい。これには簡単に始められるチュートリアルとリファレンスが入っています。

参考

PEP 327 - Decimal データ型

Facundo Batista によって著され、Facundo Batista, Eric Price, Raymond Hettinger, Aahz, Tim Peters らによって実装されました。

http://www.lahey.com/float.htm

この記事は浮動小数点数の不正確さが起こりうるたくさんの問題について、Fortran コードを使って解説しています。

https://speleotrove.com/decimal/

10 進数ベースの表現についての記述です(訳注: decimal-based は小数ベースとも 10 進数ベースとも取れるのですが、後者にしておきました)。この表現方法は標準として提案されていて、この Python の decimal 型の基礎になっています。この題材の多くが Rexx 言語設計者である Mike Cowlishaw によって著されました。

PEP 328: マルチラインインポート

言語の変更の一つは小さな文法的な微調整で、モジュールからたくさんの名前をインポートするのを簡単にするためのものです。 from module import names 文において、 names はカンマ区切りのシーケンスです。シーケンスがとても長くなった場合、同じモジュールからのインポート文を何度も書くか、行末をバックスラッシュでエスケープするかするでしょう、このように:

from SimpleXMLRPCServer import SimpleXMLRPCServer,\
            SimpleXMLRPCRequestHandler,\
            CGIXMLRPCRequestHandler,\
            resolve_dotted_attribute

Python 2.4 での文法的な変更は、単純に names を丸括弧で囲んでも良い、とするだけのものです。Python は丸括弧内の改行を無視しますので、バックスラッシュはもう必要ありません:

from SimpleXMLRPCServer import (SimpleXMLRPCServer,
                                SimpleXMLRPCRequestHandler,
                                CGIXMLRPCRequestHandler,
                                resolve_dotted_attribute)

その PEP は、全ての import 文が絶対インポートであること、相対インポートであることを示すには . 文字で開始すること、の提案もしています。PEP のこの部分は Python 2.4 では実装されていませんが、 Python 2.5 向けには完了しています。

参考

PEP 328 - マルチラインインポートと、絶対/相対インポート

Aahz 著. Multi-line imports は Dima Dorfman により実装。

PEP 331: Locale に依存しない Float/String 変換

locale モジュールを使うと、Python のソフトウェアで特定の国や言語に合わせた変換や表示の慣習を選べます。 しかし、Python の実装内のさまざまな関数が数値ロケールを 'C' のままにしておくことを要求していたため、このモジュールは数値ロケールを変更しないようにしていました。 多くの場合、その原因はコードが C ライブラリの atof() 関数を使っていることでした。

しかし数値ロケールを設定しないと、外部の C ライブラリを使う拡張モジュールでは正しいロケールが設定されず、問題が起きました。 変更のきっかけとなった例は GTK+ で、ユーザーインターフェースのウィジェットが現在のロケールに従って数値を表示していませんでした。

この PEP に記述された解法は、ロケール設定を無視して ASCII のみの変換を実施する 3 つの新しい Python API 関数を追加することです:

  • PyOS_ascii_strtod(str, ptr) and PyOS_ascii_atof(str, ptr) both convert a string to a C double.

  • PyOS_ascii_formatd(buffer, buf_len, format, d) は double を ASCII 文字列に変換します。

これらの関数のコードは GLib ライブラリ (https://developer-old.gnome.org/glib/2.26/) から来ています。 その開発者たちは親切にも該当する関数のライセンスを変更し、Python Software Foundation に寄贈してくれました。 locale モジュールは数値ロケールを変更できるようになり、GTK+ などの拡張モジュールが正しい結果を得られるようになりました。

参考

PEP 331 - Locale に依存しない Float/String 変換

Christian R. Reis 著, 実装 Gustavo Carneiro.

その他の言語変更

以下が、Python 2.4 言語コアに加えられた全ての変更点です。

  • 関数とメソッドのためのデコレータが追加されました。 (PEP 318).

  • ビルトインの set() 型と frozenset() 型が追加されました (PEP 218)。ほか新たなビルトイン関数 reversed(seq) 関数が追加されました (PEP 322)。

  • ジェネレータ式が追加されました (PEP 289).

  • いくらかの数値式は、もう 32 ビットや 64 ビットに制限されません (PEP 237).

  • from module import names ステートメントにおいて、 names を括弧で囲むことが出来るようになりました (PEP 328).

  • dict.update() メソッドが dict コンストラクタと同じ形式の引数を取れるようになりました。これには任意のマッピング、キー/値ペアのイテラブルとキーワード引数を含みます。 (Contributed by Raymond Hettinger.)

  • 文字列の ljust()、rjust()、center() メソッドに、埋め草としてスペース以外の文字を指定する省略可能な引数が加わりました。 (Raymond Hettinger による貢献です。)

  • 文字列に rsplit() メソッドも加わりました。 split() と同様に動作しますが、文字列の末尾から分割します。 (Sean Reifschneider による貢献です。)

    >>> 'www.python.org'.split('.', 1)
    ['www', 'python.org']
    'www.python.org'.rsplit('.', 1)
    ['www.python', 'org']
    
  • リストの sort() メソッドに、cmp、key、reverse という 3 つのキーワード引数が加わりました。 これらを使うと、よくある sort() の使い方を簡単に書けます。 どの引数も省略可能です。

    cmp パラメーターには、2 つの引数を取り、比較結果に応じて -1、0、+1 を返す比較関数を指定します。 この関数がリストのソートに使われます。 これまでは、これが sort() に指定できる唯一の引数でした。

    key には単一パラメータ関数を渡します。これはリスト要素を受け取り、要素の比較キーを返す関数です。リストはその比較キーを使ってソートされます。続く例はリストを大文字小文字区別なく並び替えます:

    >>> L = ['A', 'b', 'c', 'D']
    >>> L.sort()                 # 大文字・小文字を区別してソート
    >>> L
    ['A', 'D', 'b', 'c']
    >>> # 'key' パラメーターでリストをソート
    >>> L.sort(key=lambda x: x.lower())
    >>> L
    ['A', 'b', 'c', 'D']
    >>> # 従来の方法
    >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
    >>> L
    ['A', 'b', 'c', 'D']
    

    cmp パラメーターを使う最後の例は、大文字・小文字を区別せずにソートする従来の方法です。 動作はしますが、key パラメーターを使うより遅くなります。 key を使うと lower() メソッドをリストの各要素について 1 回呼び出すのに対し、cmp を使うと比較のたびに 2 回呼び出すため、key の方が lower() の呼び出しを減らせます。

    単純なキー関数や比較関数には、しばしば lambda 関数を避けて非束縛メソッドを使えます。例えば上記の大文字小文字によらない並べ替えはこのように書くのが最善です:

    >>> L.sort(key=str.lower)
    >>> L
    ['A', 'b', 'c', 'D']
    

    最後の reverse パラメータはブーリアン値を取ります。真ならばリストは逆順にソートされます。 L.sort(); L.reverse() と書く代わりにこれからは L.sort(reverse=True) と書けます。

    ソートの結果がステーブル(安定)であることが保障されるようになりました。つまり 2 つの要素が同列である場合、入力と同じ順序が保たれます。例えば人物リストを名前でソートしたのちに年齢でソートすると結果は、年齢でソートされていますが同年齢の人物は名前順です。

    (sort() への変更はすべて Raymond Hettinger によるものです。)

  • 新たに追加されたビルトイン関数 sorted(iterable) はインプレイスなメソッド list.sort() と似た振る舞いをしますが、式内で使えます。違いは:

  • 入力には任意のイテラブルを取れます;

  • 新しく構築されたコピーをソートし、オリジナルは無傷のままにします; そして

  • 式として新しいソート済みコピーを返します。

    >>> L = [9,7,8,3,2,4,1,6,5]
    >>> [10+i for i in sorted(L)]       # リスト内包表記でも使用可能
    [11, 12, 13, 14, 15, 16, 17, 18, 19]
    >>> L                               # 元のリストは変更されない
    [9,7,8,3,2,4,1,6,5]
    >>> sorted('Monty Python')          # 任意のイテラブルを入力にできる
    [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y']
    
    >>> # 辞書の内容をキーの値でソートして表示
    >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
    >>> for k, v in sorted(colormap.iteritems()):
    ...     print k, v
    ...
    black 4
    blue 2
    green 3
    red 1
    yellow 5
    

    (Contributed by Raymond Hettinger.)

  • 整数の演算で OverflowWarning が発生しなくなりました。 OverflowWarning 警告は Python 2.5 で削除されます。

  • インタプリタに新たに -m スイッチが加わりました。これは名前を取り、 sys.path にある対応するモジュールを検索し、そしてそのモジュールをスクリプトとして実行します。たとえば Python プロファイラを python -m profile で起動することが出来るようになりました。 (Contributed by Nick Coghlan.)

  • eval(expr, globals, locals) 関数と execfile(filename, globals, locals) 関数、 exec 文が locals パラメータに任意のマッピング型を受け取れるようになりました。以前は正規の Python 辞書である必要がありました。 (Contributed by Raymond Hettinger.)

  • The zip() built-in function and itertools.izip() now return an empty list if called with no arguments. Previously they raised a TypeError exception. This makes them more suitable for use with variable length argument lists:

    >>> def transpose(array):
    ...    return zip(*array)
    ...
    >>> transpose([(1,2,3), (4,5,6)])
    [(1, 4), (2, 5), (3, 6)]
    >>> transpose([])
    []
    

    (Contributed by Raymond Hettinger.)

  • モジュールのインポート中に失敗しても、部分的に初期化されたモジュールオブジェクトが sys.modules に残らなくなりました。 不完全なモジュールオブジェクトが残ると、その後の同じモジュールのインポートが成功したように見え、分かりにくいエラーにつながっていました。 (Tim Peters が修正しました。)

  • None が定数になっています。 None という名前に新しい値を割り当てようとするコードは、今では構文エラーになります。 (Contributed by Raymond Hettinger.)

最適化

  • リストとタプルのスライス処理の内部ループが最適化され、約 3 分の 1 高速になりました。 辞書の内部ループも最適化され、keys()、values()、items()、iterkeys()、itervalues()、iteritems() の性能が向上しました。 (Raymond Hettinger による貢献です。)

  • リストを拡大・縮小する仕組みが、速度とメモリ効率の両面で最適化されました。 コードの経路が効率化され、システムの realloc() の呼び出し頻度も減ったことで、リストへの追加や取り出しが高速になりました。 リスト内包表記にも効果があります。 list.extend() も最適化され、元のリストを拡張する前に引数を一時的なリストへ変換しなくなりました。 (Raymond Hettinger による貢献です。)

  • list()、tuple()、map()、filter()、zip() は、シーケンスではないものの __len__() メソッドを備える引数に対して、数倍高速になりました。 (Raymond Hettinger による貢献です。)

  • list.__getitem__()、dict.__getitem__()、dict.__contains__() メソッドは、wrapper_descriptor ではなく method_descriptor オブジェクトとして実装されるようになりました。 このアクセス方式で性能が 2 倍になり、map(mydict.__getitem__, keylist) のように高階関数の引数として渡す用途にさらに適するようになりました。 (Raymond Hettinger による貢献です。)

  • 新しいオペコード LIST_APPEND が追加され、リスト内包表記のバイトコードが単純になり、約 3 分の 1 高速になりました。 (Raymond Hettinger による貢献です。)

  • バイトコードののぞき穴最適化が改善され、より短く高速なバイトコードを生成するようになりました。 注目すべきことに、生成されたバイトコードは読みやすくもなっています。 (Raymond Hettinger による改善です。)

  • s = s + "abc" や s += "abc" という形式の文での文字列連結が、特定の状況で効率化されました。 この最適化は Jython などの他の Python 実装にはないため、依存すべきではありません。 多数の文字列を効率よく連結するには、引き続き文字列の join() メソッドを推奨します。 (Armin Rigo による貢献です。)

2.4 での最適化を総合すると、Python 2.4 は pystone ベンチマークを Python 2.3 より約 5%、Python 2.2 より約 35% 高速に実行します。 (pystone は特に優れたベンチマークではありませんが、Python の性能指標として最も広く使われています。 実際のアプリケーションで Python 2.4 がもたらす効果は、これより大きい場合も小さい場合もあります。)

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

いつものように、Python の標準ライブラリには数多くの拡張とバグ修正がありました。ここでは最も注目に値する変更について、モジュールの辞書順に列挙します。変更の完全なリストについてはソースツリーの Misc/NEWS を調べるか、あるいは全ての詳細について CVS ログに目を通してみてください。

  • asyncore モジュールの loop() 関数に count パラメーターが加わり、ポーリングループの実行回数を制限できるようになりました。 デフォルトでは、従来どおり無限に繰り返します。

  • base64 モジュールが、Base64、Base32、Base16 のエンコードとデコードについて RFC 3548 をより完全にサポートするようになりました。 大文字・小文字の同一視や代替文字集合を選択するオプションも含まれます。 (Barry Warsaw による貢献です。)

  • bisect モジュールが性能改善のために C 実装を使うようになりました。 (Contributed by Dmitry Vasiliev.)

  • Hye-Shik Chang によって保守されている東アジアのコーデックの CJKCodecs コレクションが Python 2.4 に統合されました。新たなエンコーディングは:

  • Chinese (PRC): gb2312, gbk, gb18030, big5hkscs, hz

  • Chinese (ROC): big5, cp950

  • 日本語: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp, iso-2022-jp-1, iso-2022-jp-2, iso-2022-jp-3, iso-2022-jp-ext, iso-2022-jp-2004, shift-jis, shift-jisx0213, shift-jis-2004

  • Korean: cp949, euc-kr, johab, iso-2022-kr

  • ほか、新たなエンコーディングが追加されています: HP Roman8, ISO_8859-11, ISO_8859-16, PCTP-154, TIS-620.

  • UTF-8 と UTF-16 のコーデックが、部分的な入力をより適切に扱うようになりました。 これまで StreamReader クラスは追加のデータを読み込もうとするため、ストリームからのデコードを再開できませんでした。 read() メソッドは、読み取れるだけのデータを返し、次の呼び出しで前回の続きからデコードを再開するようになりました。 (Walter Dörwald による実装です。)

  • さまざまな専用のコレクションデータ型のための、新しい collections モジュールができました。 現時点では、両端から効率的に要素を追加・削除できる両端キュー deque という一つの型だけが含まれています。

    >>> from collections import deque
    >>> d = deque('ghi')        # 3 つの要素を持つ新しい deque を作る
    >>> d.append('j')           # 右側に新しい要素を追加
    >>> d.appendleft('f')       # 左側に新しい要素を追加
    >>> d                       # deque の表現を表示
    deque(['f', 'g', 'h', 'i', 'j'])
    >>> d.pop()                 # 右端の要素を取り除いて返す
    'j'
    >>> d.popleft()             # 左端の要素を取り除いて返す
    'f'
    >>> list(d)                 # deque の内容をリストにする
    ['g', 'h', 'i']
    >>> 'h' in d                # deque を検索
    True
    

    queue や threading などのモジュールが collections.deque を活用し、性能を向上させています。 (Raymond Hettinger による貢献です。)

  • ConfigParser のクラスが少し拡張されました。 read() メソッドは正常に解析できたファイルのリストを返すようになり、set() メソッドは value 引数が文字列でなければ TypeError を送出するようになりました。 (John Belmonte と David Goodger による貢献です。)

  • curses モジュールが、ncurses の拡張機能 use_default_colors() をサポートするようになりました。 端末が透明表示に対応するプラットフォームでは、透明な背景を使えます。 (Jörg Lehmann による貢献です。)

  • difflib モジュールに HtmlDiff クラスが加わり、2 つの版のテキストを左右に並べて比較する HTML テーブルを作れるようになりました。 (Dan Gass による貢献です。)

  • The email package was updated to version 3.0, which dropped various deprecated APIs and removes support for Python versions earlier than 2.3. The 3.0 version of the package uses a new incremental parser for MIME messages, available in the email.FeedParser module. The new parser doesn't require reading the entire message into memory, and doesn't raise exceptions if a message is malformed; instead it records any problems in the defect attribute of the message. (Developed by Anthony Baxter, Barry Warsaw, Thomas Wouters, and others.)

  • heapq モジュールが C で実装され、速度が 10 倍になったことで、大量のデータの処理に適するようになりました。 また、全体をソートするコストをかけずに、ヒープを使ってデータセットの大きい方または小さい方から N 個の値を見つける、新しい関数 nlargest() と nsmallest() が加わりました。 (Raymond Hettinger による貢献です。)

  • httplib モジュールに、HTTP 関連の RFC 文書で定義された HTTP ステータスコードの定数が加わりました。 定数名には OK、CREATED、CONTINUE、MOVED_PERMANENTLY などがあります。 一覧は pydoc で確認してください。 (Andrew Eland による貢献です。)

  • imaplib モジュールが IMAP の THREAD コマンドをサポートするようになりました (Yves Dionne による貢献です)。 また、新しい deleteacl() メソッドと myrights() メソッドが加わりました (Arnaud Mazin による貢献です)。

  • itertools モジュールに groupby(iterable[, *func*]) 関数が加わりました。 iterable は、反復して要素の列を取り出せるものです。 省略可能な func パラメーターは、要素を受け取ってキーの値を返す関数で、省略すると要素自体がキーになります。 groupby() はキーの値が等しい要素を部分列にまとめ、キーの値とその部分列のイテレータからなる 2 要素のタプルを順に返します。

    分かりやすい例を示します。 key 関数は数が偶数か奇数かを返すだけなので、groupby() は連続する奇数や偶数のまとまりを返します。

    >>> import itertools
    >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14]
    >>> for key_val, it in itertools.groupby(L, lambda x: x % 2):
    ...    print key_val, list(it)
    ...
    0 [2, 4, 6]
    1 [7]
    0 [8]
    1 [9, 11]
    0 [12, 14]
    >>>
    

    groupby() は通常、ソート済みの入力に対して使います。 groupby() の処理は Unix の uniq フィルターに似ており、重複した要素の除去、計数、検出に便利です。

    >>> word = 'abracadabra'
    >>> letters = sorted(word)   # 文字列をソートされた文字のリストにする
    >>> letters
    ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
    >>> for k, g in itertools.groupby(letters):
    ...    print k, list(g)
    ...
    a ['a', 'a', 'a', 'a', 'a']
    b ['b', 'b']
    c ['c']
    d ['d']
    r ['r', 'r']
    >>> # 重複しない文字を列挙
    >>> [k for k, g in groupby(letters)]
    ['a', 'b', 'c', 'd', 'r']
    >>> # 文字の出現回数を数える
    >>> [(k, len(list(g))) for k, g in groupby(letters)]
    [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
    

    (Contributed by Hye-Shik Chang.)

  • itertools には tee(iterator, N) という新たな関数も追加されています。これは iterator の、独立した N 個の複製イテレータを返します。 N は省略されればデフォルトは 2 です。:

    >>> L = [1,2,3]
    >>> i1, i2 = itertools.tee(L)
    >>> i1,i2
    (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
    >>> list(i1)               # 最初のイテレータを最後まで進める
    [1, 2, 3]
    >>> list(i2)               # 2 つ目のイテレータを最後まで進める
    [1, 2, 3]
    

    tee() は、イテレータが返した値のコピーを保持する必要があり、最悪の場合はすべての値を保持することになります。 そのため、長い入力列で先行するイテレータが後続のイテレータより大幅に先へ進み得る場合は、注意して使ってください。 進み具合の差が大きいなら、代わりに list() を使ってもよいでしょう。 イテレータ同士が近い位置を進む場合には tee() が理想的です。 用途には、位置の記録、ウィンドウ処理、先読みイテレータなどがあります。 (Raymond Hettinger による貢献です。)

  • locale モジュールに、特定のエンコーディングを指定する bind_textdomain_codeset() や、選んだエンコーディングでメッセージを返す l*gettext() 系の関数などが追加されました。 (Gustavo Niemeyer による貢献です。)

  • ログの設定を簡単にするため、logging パッケージの basicConfig() 関数にキーワード引数が追加されました。 デフォルトではメッセージを標準エラーへ記録しますが、キーワード引数を指定すると、ファイルへの記録、ログの書式の変更、ログレベルの設定などができます。 例えば次のようになります。

    import logging
    logging.basicConfig(filename='/var/log/application.log',
        level=0,  # Log all messages
        format='%(levelname):%(process):%(thread):%(message)')
    

    logging パッケージには、簡便な log(level, msg) メソッドや、一定の時間間隔でログファイルをローテーションする TimedRotatingFileHandler クラスも加わりました。 以前からあった RotatingFileHandler は、ファイルが一定のサイズを超えたらログをローテーションするものでした。 どちらのクラスも新しい BaseRotatingHandler クラスを継承しており、これを使って別のローテーション方式のハンドラーも実装できます。

    (Changes implemented by Vinay Sajip.)

  • marshal モジュールが、データ構造のアンパックで内部化した文字列を共有するようになりました。これはある種の pickle 文字列のサイズを切り詰めるでしょうが、主要な効能は .pyc ファイルが顕著に小さくなることです。(Contributed by Martin von Löwis.)

  • nntplib モジュールの NNTP クラスに、単一のニュースグループや一定の範囲のグループの説明を取得する description() メソッドと descriptions() メソッドが加わりました。 (Jürgen A. Erhard による貢献です。)

  • operator モジュールに 2 つの関数 attrgetter(attr) と itemgetter(index) が追加されています。両関数ともに、単一引数を取ってそれに対応する属性かアイテムを返す呼び出し可能オブジェクトを返します。これら呼び出し可能オブジェクトは map() や sorted() とともに使う際の優れたデータ抽出器になります。例えば:

    >>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)]
    >>> map(operator.itemgetter(0), L)
    ['c', 'd', 'a', 'b']
    >>> map(operator.itemgetter(1), L)
    [2, 1, 4, 3]
    >>> sorted(L, key=operator.itemgetter(1)) # タプルの 2 番目の要素でリストをソート
    [('d', 1), ('c', 2), ('b', 3), ('a', 4)]
    

    (Contributed by Raymond Hettinger.)

  • optparse モジュールが色々更新されました。モジュールはメッセージを gettext.gettext() を通して Optik のヘルプとエラーメッセージを国際化するのを可能にしています。オプションのヘルプメッセージは文字列 '%default' を含めることが出来るようになっており、これはオプションのデフォルト値に置換されます。(Contributed by Greg Ward.)

  • 長期的には、将来の Python リリースで rfc822 モジュールを非推奨にし、email パッケージへ置き換える計画です。 そのため、email.Utils.formatdate 関数が rfc822.formatdate() の代わりに使えるよう変更されました。 新しい電子メール処理のコードは、この点を考慮して書くとよいでしょう。 (Anthony Baxter による変更です。)

  • os モジュールに urandom(n) が追加されました。これは n バイトの乱数データを含む文字列を返します。この関数はプラットフォーム固有の乱数発生源にアクセスします。例えば Linux での /dev/urandom や Windows での CryptoAPI です。 (Contributed by Trevor Perrin.)

  • もう一つの新規関数 os.path.lexists(path) は path によって指定されたファイルがそれがシンボリックリンクかどうかによらず、存在している場合に真を返します。これは、既存の os.path.exists(path) 関数が path がシンボリックリンクでその指し先が存在しない場合に偽を返すのとは異なります。 (Contributed by Beni Cherniavsky.)

  • os モジュールの基盤となる posix モジュールに、新しい getsid() 関数が加わりました。 (J. Raynor による貢献です。)

  • poplib モジュールが POP over SSL をサポートするようになりました. (Contributed by Hector Urtubia.)

  • profile モジュールが C 拡張の関数をプロファイル出来るようになりました。 (Contributed by Nick Bastin.)

  • random モジュールに、N ビットの長整数を返す getrandbits(N) メソッドが加わりました。 既存の randrange() メソッドも、適切な場合には getrandbits() を使うようになり、任意の大きさの乱数を効率よく生成できるようになりました。 (Raymond Hettinger による貢献です。)

  • re モジュールの正規表現言語が拡張されて、単純な条件式 (?(group)A|B) を書けるようになっています。 group は数値グループ ID か正規表現内で (?P<group>...) で定義したグループ名のどちらかです。指定したグループが合致した場合は、正規表現パターン A が文字列に対してテストされ、そうでなければパターン B が代わりに試されます。(Contributed by Gustavo Niemeyer.)

  • re モジュールはもう再帰をすることはありません。Gustavo Niemeyer による膨大な量の仕事のおかげです。再帰する正規表現エンジンでは、ある種のパターンでは大量の C スタック空間を消費し、スタックのオーバーフローを起こすことがありました。例えば表現 (a|b)+ が文字 a から成る 3 万バイトの文字列に対してマッチすると、一文字ごとに一つのスタックフレームを消費していました。Python 2.3 ではスタックオーバーフローのチェックを試みて RuntimeError を投げようとしましたが、ある種のパターンではチェックをすり抜けてしまって、運が悪いとセグメンテーション違反を起こしていました。Python 2.4 の正規表現エンジンではこのパターンと問題を起こすことなくマッチ出来ます。

  • signal モジュールは、signal.signal() 関数の引数に対するエラーチェックを厳しくしました。 例えば SIGKILL シグナルにはハンドラーを設定できません。 以前の Python はこれを黙って受け付けていましたが、2.4 では RuntimeError 例外を送出します。

  • socket モジュールに 2 つの関数が加わりました。 socketpair() は接続されたソケットのペアを返し、getservbyport(port) はポート番号に対応するサービス名を検索します。 (Dave Cole と Barry Warsaw による貢献です。)

  • sys.exitfunc() 関数が非推奨となりました。 複数の終了処理関数の呼び出しを正しく扱える、既存の atexit モジュールを使ってください。 将来的に sys.exitfunc() は atexit だけが使う、完全に内部用のインターフェースになります。

  • tarfile モジュールがデフォルトで GNU フォーマットを生成するようになっています。 (Contributed by Lars Gustäbel.)

  • threading モジュールで、スレッドローカルなデータを簡潔に扱えるようになりました。 属性の値をスレッドごとに保持する local クラスが含まれています。

    import threading
    
    data = threading.local()
    data.number = 42
    data.url = ('www.python.org', 80)
    

    ほかのスレッドは、number 属性と url 属性にそれぞれ独自の値を設定・取得できます。 local のサブクラスを作り、属性を初期化したりメソッドを追加したりできます。 (Jim Fulton による貢献です。)

  • timeit モジュールはループを計測中は周期的なガーベージコレクションを自動で無効化するようになりました。この変更により、繰り返しの計測の比較がやりやすくなります。 (Contributed by Raymond Hettinger.)

  • weakref モジュールがサポートするオブジェクトが非常に幅広くなりました。これには Python 関数、クラスインスタンス, set, frozenset, deque, array と正規表現パターンオブジェクトが含まれます。(Contributed by Raymond Hettinger.)

  • xmlrpclib モジュールが、1 回の HTTP 操作で複数の XML-RPC 呼び出しを送る multi-call 拡張に対応しました。 (Brian Quinlan による貢献です。)

  • mpz、rotor、xreadlines モジュールが削除されました。

cookielib

cookielib ライブラリは、Cookie モジュールのサーバー側のクッキー処理に対応する、クライアント側の HTTP クッキー処理をサポートします。 クッキーはクッキージャーに格納されます。 ライブラリは、Web サーバーから受け取ったクッキーをクッキージャーへ自動的に保存し、サーバーへの接続時にそこから取り出します。 Web ブラウザーと同じく、クッキーを受け入れるかどうかはポリシーオブジェクトが制御します。

セッションを跨いでクッキーを記憶するために、2 つのクッキー瓶実装が提供されています。一つは Netscape フォーマットでクッキーを記憶するのでアプリケーションは Mozilla か Lynx のクッキーファイルを使え、もう一つは Perl の libwww ライブラリと同じフォーマットでクッキーを記憶します。

urllib2 が cookielib と連携するよう変更されました。 HTTPCookieProcessor が、URL へのアクセスに使うクッキージャーを管理します。

このモジュールは John J. Lee により寄稿されました。

doctest

Edward Loper と Tim Peters のおかげにより、 doctest モジュールに注目に値するリファクタリングが入りました。テストはこれまで通り単純に doctest.testmod() を実行するすることで行えますが、リファクタリングはモジュールの操作をカスタマイズする色々な手段を提供してくれます。

新しい DocTestFinder クラスは、指定したオブジェクトの docstring からテストを取り出します。

def f (x, y):
    """>>> f(2,2)
4
>>> f(3,2)
6
    """
    return x*y

finder = doctest.DocTestFinder()

# DocTest インスタンスのリストを取得
tests = finder.find(f)

続いて、新しい DocTestRunner クラスが個々のテストを実行し、結果の要約を作成できます。

runner = doctest.DocTestRunner()
for t in tests:
    tried, failed = runner.run(t)

runner.summarize(verbose=1)

上の例はこのような出力を生成します:

1 items passed all tests:
   2 tests in f
2 tests in 1 items.
2 passed and 0 failed.
Test passed.

DocTestRunner は OutputChecker クラスのインスタンスを使って、期待する出力と実際の出力を比較します。 このクラスの動作はさまざまなフラグで調整できます。 より高度な使い方をしたい場合は、OutputChecker のまったく新しいサブクラスを書くこともできます。

デフォルトの出力チェッカーは多くのお手軽機能を持っています。例えば doctest.ELLIPSIS オプションフラグは、出力の期待値内での省略記号 (...) と任意文字列を一致するとみなし、瑣末な部分が変化するような出力に簡単に適合するように出来ます:

def o (n):
    """>>> o(1)
<__main__.C instance at 0x...>
>>>
"""

もう一つの特殊文字列 <BLANKLINE> は空行に合致します:

def p (n):
    """>>> p(1)
<BLANKLINE>
>>>
"""

もう一つの新機能は出力の diff スタイル出力で、オプションフラグに doctest.REPORT_UDIFF (unified diffs), doctest.REPORT_CDIFF (context diffs), doctest.REPORT_NDIFF (delta-style) を指定することで利用出来ます。例えば以下があるとして:

def g (n):
    """>>> g(4)
here
is
a
lengthy
>>>"""
    L = 'here is a rather lengthy list of words'.split()
    for word in L[:n]:
        print word

上の関数のテストを doctest.REPORT_UDIFF を指定して実行すると、次の出力が得られます。

**********************************************************************
File "t.py", line 15, in g
Failed example:
    g(4)
Differences (unified diff with -expected +actual):
    @@ -2,3 +2,3 @@
     is
     a
    -lengthy
    +rather
**********************************************************************

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

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

  • 拡張関数からの戻り値として一般的に使うための 3 つの便利なマクロが追加されています: Py_RETURN_NONE, Py_RETURN_TRUE, Py_RETURN_FALSE (Contributed by Brett Cannon.)

  • もう一つの新しいマクロ Py_CLEAR は、obj の参照カウントを減らし、obj をヌルポインターに設定します。 (Jim Fulton による貢献です。)

  • 新規関数 PyTuple_Pack(N, obj1, obj2, ..., objN) は Python オブジェクトの可変長引数リストからタプルを構築します。 (Contributed by Raymond Hettinger.)

  • 新規関数 PyDict_Contains(d, k) は、処理内で起こる例外のマスキングなしでの高速なルックアップを実装しています。 (Contributed by Raymond Hettinger.)

  • Py_IS_NAN マクロは、float または double の引数 X が NaN なら 1 を返します。 (Tim Peters による貢献です。)

  • C コードでは、新しい PyEval_ThreadsInitialized() 関数でスレッド操作が行われたかどうかを調べ、不要なロックを避けられます。 この関数が偽を返す場合、ロック操作は不要です。 (Nick Coghlan による貢献です。)

  • 新規関数 PyArg_VaParseTupleAndKeywords() は PyArg_ParseTupleAndKeywords() と同じですが、たくさんの引数の代わりに va_list を取ることだけが違います。(Contributed by Greg Chapman.)

  • 新しいメソッドフラグ METH_COEXIST によって、スロットで定義された関数と同名の PyCFunction を共存させられます。 これにより、set.__contains__() などのメソッドへのアクセス時間を半減できます。 (Raymond Hettinger による貢献です。)

  • Python コアの開発を支援するため、インタープリタ自体の追加のプロファイリング機能を有効にしてビルドできるようになりました。 configure スクリプトに --enable-profiling を指定すると gprof でインタープリタをプロファイルでき、--with-tsc を指定すると Pentium のタイムスタンプカウンターレジスターを使ったプロファイリングが有効になります。 --with-tsc という名前は少し不正確です。 この機能は PowerPC でも動作しますが、そのアーキテクチャでは該当するレジスターを「TSC レジスター」とは呼ばないためです。 (Jeremy Hylton による貢献です。)

  • tracebackobject 型は PyTracebackObject に改名されました。

ポート特有の変更

  • Windows ポートは MSVC++ 6 と 7.1 でビルド出来ます。 (Contributed by Martin von Löwis.)

Python 2.4 への移植

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

  • 大き過ぎる値を持つ左シフトと 16 進/ 8 進定数が FutureWarning を引き起こした上で 32 ビットまたは 64 ビットに制限される、という振る舞いはもうしません。代わりに長整数を返します。

  • 整数の演算で OverflowWarning が発生しなくなりました。 OverflowWarning 警告は Python 2.5 で削除されます。

  • The zip() built-in function and itertools.izip() now return an empty list instead of raising a TypeError exception if called with no arguments.

  • datetime モジュールの date と datetime のインスタンスを比較できなくなりました。 異なるクラスのインスタンスは常に等しくないと判定され、大小比較 (<、>) は TypeError を送出します。

  • dircache.listdir() は、空のリストを返す代わりに、例外を呼び出し側へ伝えるようになりました。

  • LexicalHandler.startDTD は、これまで公開識別子とシステム識別子を逆の順番で受け取っていました。 これは修正されたため、誤った順番に依存しているアプリケーションは修正する必要があります。

  • fcntl.ioctl() は mutate_flag 引数が省略されて問題に関係がある場合は警告を出します。

  • tarfile モジュールがデフォルトで GNU フォーマットを生成するようになっています。

  • モジュールのインポート中に失敗しても、部分的に初期化されたモジュールオブジェクトが sys.modules に残らなくなりました。

  • None が定数になっています。 None という名前に新しい値を割り当てようとするコードは、今では構文エラーになります。

  • signal.signal() 関数は、これまで黙って受け付けていた一部の不正な値に対し、RuntimeError 例外を送出するようになりました。 例えば SIGKILL シグナルにハンドラーを設定することはできなくなりました。

謝辞

著者は提案の申し出や修正、様々なこの記事の草稿の助けをしてくれた以下の人々に感謝します: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider, Sadruddin Rejeb.