What’s New in Python 2.1

Author:A.M. Kuchling

はじめに

この記事はPython 2.1の新機能について説明します。Python 2.1には Python 2.0ほど多くの変更点はありませんが、楽しい驚きがあります。2.1はPythonの拡張計画(PEP)を使い動かす最初のリリースであり、大きい変更点のほとんどは、より詳細なドキュメントや変更のための設計原理を提供するPEPに付随しています。この記事は新機能について網羅していませんが、Pythonプログラマのための新機能について概要を示します。特に興味のある任意の新機能の詳細については、Python 2.1ドキュメントか特定のPEPを参照してください。

Python開発チームの最近の目標の一つとして新しいリリースのペースを上げており、一つのリリースにつき6~9ヶ月ごとにリリースしています。2.1はこの速いペースになって出てきた最初のリリースで、初のアルファ版は、2.0の最終版がリリースされた3ヶ月後の1月に登場しました。

Python 2.1の最終版は2001年4月17日に作成されました。

PEP 227: 入れ子状のスコープ

Python2.1における最も大きな変更点はPythonのスコープルールです。Python2.0では、ある指定された時点である変数の名前を検索するために多くても3つの名前空間、つまりローカル、モジュールレベル、ビルトイン名前空間しか使われませんでした。このことは直感的な期待と一致せずしばしば人々を驚かせました。例えば、入れ子になった再帰関数の定義は動きません:

def f():
    ...
    def g(value):
        ...
        return g(value-1) + 1
    ...

名前 g はローカルの名前空間にもモジュールレベルの名前空間にも紐付かないので、関数 g() は常に NameError 例外を上げます。これは実際には大した問題ではありません (このような内部関数を再帰的に定義する頻度はそう多くありません)が、 lambda ステートメントをより使いにくくするのでこれについては問題です。 lambda を使うコードにおいて、デフォルトの引数としてこれらを渡してコピーされるローカル変数を頻繁に見かけます。:

def find(self, name):
    "Return list of any entries equal to 'name'"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    return L

過度な関数型スタイルで書かれた Python コードの可読性は、結果的にはひどく苦痛を感じるものですね。

Python 2.1の最も重要な変更点は、この問題を解決するために静的なスコープが追加されたことです。最初の効果として、name=name という例ではデフォルトの引数は必要ありません。簡単に言えば、指定された引数名が関数内の値に割り当てられない場合(defclass または import ステートメントの割り当てによって)、変数の参照は外側のスコープのローカル名前空間で検索されます。ルールや実装の詳細はPEPで参照できます。

この変更は、同じ変数名がモジュールレベルと関数の定義が含まれている関数内のローカルの両方で変数名として使用されているコードで、互換性の問題を引き起こす可能性があります。ですがむしろ気にしなくてよいでしょう。そのようなコードはそもそも最初から相当こんがらかっているので。

この変更の副作用の一つは、 from module import *exec の両ステートメントが特定の条件下の関数スコープ内で不正となることです。 Python のリファレンスマニュアルははじめからずっと from module import * はトップレベルモジュールでのみ合法であると言ってきましたが、以前の CPython インタプリタはこれを一度も強制していませんでした。入れ子になったスコープ実装の一環として、Python のソースをバイトコードに変換するコンパイラは、内包されたスコープ内の変数にアクセスするために別のコードを生成する必要があります。 from module import *, exec はコンパイラにこれを理解することを不可能にしてしまいます。なぜならそれらはコンパイル時にはわからないローカル名前空間に名前を追加するからです。それゆえ、もし関数が関数定義を含んだり自由な変数に lambda の語句を含んだりする場合、コンパイラは SyntaxError 例外を上げて知らせます。

前述した説明を少し明確にするため、例を挙げます:

x = 1
def f():
    # The next line is a syntax error
    exec 'x=2'
    def g():
        return x

exec 文を含む 4 行目は文法エラーです。 exec としては新しいローカル変数 x を定義したいのですが、これは g() からアクセスされなければなりません。

これは実際には大した制約でもないはずです。 exec が Python コードで使われるのは稀です(使われているとしたら大抵どこか貧弱な設計であることの証)。

互換性の問題が考慮されて、入れ子のスコープは段階的導入につながりました; Python 2.1 ではそれらはデフォルトで有効になっていませんが、PEP 236 に記載されているように、future 文を使用してモジュール内でオンにすることができます。(PEP 236 の更なる議論について、続くセクションを参照してください。) Python 2.2では入れ子になったスコープがデフォルトになり、それをオフにする方法はありませんが、ユーザは 2.1 の全ライフタイムを通して、導入の結果起きるあらゆる破損を修正し続けるでしょう。

参考

PEP 227 - 静的に入れ子になったスコープ

Jeremy Hylton著、実装

PEP 236: __future__ 指示文

ネストされたスコープへのこの対応は、リリース 2.1 ではコードを壊すことの危険性について広く懸念されており、 Pythoneer 達に保守的なアプローチを選ばせるには十分でした。このアプローチは、必須とするリリース N+1 に対する、 リリース N でのオプション機能として有効化という序奏、というものです。

この構文は __future__ という名の予約モジュールを使う from...import ステートメントを使用します。ネストしたスコープは以下のステートメントで有効にできます。

from __future__ import nested_scopes

普通 の import ステートメントに見えますが、実は違います; このような未来のステートメントが置かれる場所には厳格なルールがあります。これらはモジュールの冒頭にしか置けませんし、必ず何らかのPythonコードや正規の import ステートメントの前になければなりません。それと言うのもこのようなステートメントは、Pythonのバイトコードコンパイラがコードを解析し、バイトコードを生成する方法に影響しますので、生成されるバイトコードとなるステートメントの前になくてはならないのです。

参考

PEP 236 - バック・トゥ・ザ・ __future__

Tim Peter著、Jeremy Hylton主実装

PEP 207: 拡張比較

In earlier versions, Python’s support for implementing comparisons on user-defined classes and extension types was quite simple. Classes could implement a __cmp__() method that was given two instances of a class, and could only return 0 if they were equal or +1 or -1 if they weren’t; the method couldn’t raise an exception or return anything other than a Boolean value. Users of Numeric Python often found this model too weak and restrictive, because in the number-crunching programs that numeric Python is used for, it would be more useful to be able to perform elementwise comparisons of two matrices, returning a matrix containing the results of a given comparison for each element. If the two matrices are of different sizes, then the compare has to be able to raise an exception to signal the error.

Python2.1で、このニーズを満たすために拡張比較が追加されました。Pythonのクラスは、<<=>>===!= の各演算を個別にオーバーロードできます。この新しい特殊メソッドの名前は:

演算

メソッド名

< __lt__()
<= __le__()
> __gt__()
>= __ge__()
== __eq__()
!= __ne__()

(特殊メソッドはFortranの .LT..LE. 等々の演算子にちなんで命名されています。プログラマはほぼ確実にこれらの名前を熟知していますので、覚えやすいでしょう。)

これらの特殊メソッドは method(self, other) の形式になっており、self が演算子の左辺、other が右辺のオブジェクトになります。例えば、式 A < BA.__lt__(B) を呼び出します。

これらの特殊メソッドは何でも、つまり真偽値や行列、リストや他のPython オブジェクトを返せます。もし比較が不可能であったり、矛盾していたり、意味がない場合は、代わりに例外を上げることができます。

ビルトインの cmp(A,B)() 関数は拡張比較機構を利用出来、使用する比較演算を指定する省略可能引数を受け付けるようになっています。指定には文字列 "<", "<=", ">", ">=", "==", or "!=" のいずれか一つを渡します。省略可能のその 3 番目引数が省略されて呼ばれれば、 cmp() は以前のバージョンの Python のように -1, 0, または +1 だけを返します; 指定されれば、それはその適切なメソッドを呼び出し、任意の Python オブジェクトを返せます。(訳注: 2015年の今となって、ここに書かれている cmp の仕様が実在したのか不明な状態になっている。ビルトインの cmp リファレンスにはこれに関係する履歴は書かれていない。What’s New を 2.7 まで追いかけても以後変更された記録はない。)

C プログラマにとって興味深い関連する変更があります。型オブジェクトに新しい tp_richcmp スロットと、この拡張された比較を行うAPIが追加されました。ここではC APIについて言及しませんが、あながた関連する関数のリストを見たければ、PEP 207かバージョン2.1のC APIドキュメントを参照してください。

参考

PEP 207: 拡張比較

David Ascher によるかつての仕事に大きく拠りますが Guido van Rossum によって著され、実装されました。

PEP 230: 警告フレームワーク

10 年の間に、Python は途中で廃止されたモジュールと機能の特定の番号を蓄積してきました。どれだけのコードが活用されているか知る術はないので、機能を削除して問題ないか把握することは困難です。その機能に依存するプログラムは一つもないかもしれませんし、たくさんあるかもしれません。より構造化された方法で古い機能を削除できるようにするために、警告のフレームワークが追加されました。Python の開発者がある機能を取り除きたいときは、まずは Python の次のバージョンで警告を引き起こします。続く Python バージョンで開発者はその機能を削除出来、ユーザは古い機能の使用を取り除くために Python リリースサイクル一つ丸々使えます。

Python 2.1 はこのスキームで使われる警告フレームワークを追加します。また、警告の表示機能や表示させたくない警告を除外する機能を提供する、 warnings モジュールを追加します。サードパーティーのモジュールはまた、彼らがサポート対象外にしたい古い機能を非推奨と知らしめるのにこのフレームワークを利用できます。

例えば、Python2.1では regex モジュールは廃止されたので、これをインポートすると警告が表示されます:

>>> import regex
__main__:1: DeprecationWarning: the regex module
         is deprecated; please use the re module
>>>

警告は warnings.warn() 関数を呼び出すことで発行できます:

warnings.warn("feature X no longer supported")

最初のパラメータは警告メッセージです。任意追加のパラメータは、特定の警告カテゴリを指定するために利用することができます。

特定の警告を無効にするためにフィルターを追加できます。また警告を抑止するためにメッセージまたはモジュール名に正規表現が適用できます。例えば regex モジュールを使ったプログラムで、今すぐには re モジュールに変換する時間をかけられないプログラムがあるとします。警告は以下呼び出しにより抑制できます:

import warnings
warnings.filterwarnings(action = 'ignore',
                        message='.*regex module is deprecated',
                        category=DeprecationWarning,
                        module = '__main__')

これは __main__ モジュール内で引き起こされた DeprecationWarning 警告だけに適用され、 regex モジュールが非推奨となったことについてのメッセージにマッチする正規表現を適用するフィルタを追加し、そして結果としてそのような警告は無視されることになります。警告を一回きりの表示にしたり、違反コードが実行されるたびに表示したり、警告ではなく例外に切り替えてプログラム停止することも出来ます(例外が普通の方法で捕捉されない限り、です、もちろん)。

関数は、警告を発行するための Python の C API にも追加されました。詳細については PEP 230 または Python の API ドキュメントを参照してください。

参考

PEP 5 - 言語の進化のためのガイドライン

Python から古い機能を削除する時に従うべき手順を示すため、 Paul Prescod により書かれました。当 PEP に記載された方針は正式に採用されていませんが、最終的な方針も Prescod の提案とおそらくさほど違いはないでしょう。

PEP 230 - 警告フレームワーク

Guido van Rossum 著、実装

PEP 229: 新しいビルドシステム

Python のコンパイル時、ユーザはソースツリーの中に入って、様々な追加モジュールを有効にするために Modules/Setup ファイルを編集しなければなりませんでした; デフォルトのセットは比較的小さくて、ほとんどの Unix プラットフォームで、コンパイルするモジュールを制限しています。これは、特に Linux に顕著ですが、たくさんの追加機能を持った Unix プラットフォームでは、Python インストレーションはしばしば、そう出来るのに有用なモジュールを全く含まない、といったことが起こることを意味しています。

Python 2.0 は、配布と拡張のインストールをするためのモジュールのセットである Distutils を追加しました。Python 2.1 では Distutils を、たくさんの拡張モジュールの標準ライブラリを、サポートする機器かどうかを自動検出してコンパイルするのに使っています。これが Python インストレーションをより簡単に、より機能的とするものであることが期待されています。

モジュールを有効化するために Modules/Setup を編集する必要性の代わりに、Python ソースツリーのトップレベルディレクトリにある setup.py スクリプトがビルド時に実行され、システムのモジュールとヘッダファイルを調べることによって、どのモジュールが有効に出来るのかを検出しようと試みます。モジュールが Modules/Setup 内でそう構成されていれば、 setup.py スクリプトはそのモジュールをコンパイルしようとはせずに Modules/Setup ファイル内容に従います。これは特定のプラットフォームで必要となるヘンチクリンなコマンドラインフラグやライブラリフラグを特定する手段も与えてくれます。

もう一つの大きなビルド機構の変更点は Neil Schemenauer による再構成で、今や Python は、トップディレクトリと Python/, Parser/, Objects/, Modules/ サブディレクトリにあった別々の Makefile が再帰的にビルドする代わりに、再帰をしないトップレベルの単一 makefile を使うようになっています。このことで Python のビルドは速くなり、 Makefile をもてあそぶのが単純明快になっています。

参考

PEP 229 - Distutils を使った Python のビルド

A.M. Kuchling 著、実装

PEP 205: 弱参照

weakref モジュールを通して利用出来る弱参照(weak references)は、ささやかですが有用な、Python プログラマの道具箱に新たに加わったデータ型です。

オブジェクトへの参照(辞書内やリスト内を思い浮かべてください)を記憶しておくということは、オブジェクトを生き永らえさせるという副作用を持っています。少しばかりの、この振る舞いが望ましくない特殊なケースがあります。オブジェクトのキャッシュがその最もありがちな一つで、もう一つはツリーのようなデータ構造での循環参照です。

例えば、 ひとさまの関数 f(x) の結果をキャッシュしておくメモ化関数を考えてみましょう。関数 f(x) の引数ごとに辞書に記憶します:

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        return _cache[x]

    retval = f(x)

    # Cache the returned object
    _cache[x] = retval

    return retval

このバージョンは整数のような単純なものにはうまく働きますが、副作用を持っています; 辞書 _cache は戻り値への参照を保持するので、それらは Python プロセスが終了してクリーンアップされない限り、解放されません。整数であればそれは気にすることではありませんが、f() がオブジェクトや何かメモリをたくさん使うようなデータ構造を返すならば、これは問題になるかもしれません。

弱参照は、オブジェクトをその時間を超えて生き永らえさせたくないキャッシュの実装のための手段を提供します。オブジェクトがアクセス出来るのが弱参照からのみである場合、そのオブジェクトは解放されて、その弱参照は参照しているそのオブジェクトがもはや存在しないことを表明します。オブジェクト obj への弱参照を作るには、 wr = weakref.ref(obj) とします。参照されているオブジェクトは、それがあたかも関数であったかのように弱参照を「コール」することで得ます: wr() 。それは参照されたオブジェクトを返すか、もう存在していないのであれば None を返します。

これでオブジェクトを生き残らせないキャッシュを使う memoize() を、キャッシュ内に弱参照を記憶するというやり方で書けます:

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        obj = _cache[x]()
        # If weak reference object still exists,
        # return it
        if obj is not None: return obj

    retval = f(x)

    # Cache a weak reference
    _cache[x] = weakref.ref(retval)

    return retval

weakref モジュールでは、弱参照のように振舞うプロキシオブジェクトも作れます — プロキシオブジェクトによってのみ参照されるオブジェクトが解放されます – オブジェクトを取り出すために明示的に「呼び出す」必要をなくすためにプロキシは、全てのオブジェクトへの操作を、オブジェクトが生きている限り透過的に転送します。オブジェクトが解放された場合、プロキシを使おうとすると weakref.ReferenceError 例外が起こります:

proxy = weakref.proxy(obj)
proxy.attr   # Equivalent to obj.attr
proxy.meth() # Equivalent to obj.meth()
del obj
proxy.attr   # raises weakref.ReferenceError

参考

PEP 205 - 弱参照

Fred L. Drake, Jr. 著、実装

PEP 232: 関数の属性

Python 2.1 では、関数に任意の情報をアタッチさせる(付随させる)ことが出来るようになりました。人々はしばしば関数やメソッドについての情報を保持するのに docstring を使ってきました。というのも __doc__ だけが唯一関数に任意の情報をアタッチ出来る方法だったからです。例えば、Zope ウェブアプリケーションでは、関数は docstring に情報を持つことによって公開アクセスのために安全かどうかマークされ、John Aycock の SPARK 解析フレームワークでは docstring は BNF 文法記述の部分を、解析のために保持していました。この「詰め込み」は嘆かわしいことです。docstring はまったくもって関数のドキュメンテーションを保持するのに意図されたものです。例えば Zope では自分のために行儀よく関数にドキュメント付け出来ないということです。

ついに関数に、任意の属性をセットし、取り出すことが出来るようになりました。普通の Python 構文で出来ます:

def f(): pass

f.publish = 1
f.secure = 1
f.grammar = "A ::= B (C D)*"

属性を含んだ辞書に、関数の属性 __dict__ としてアクセス出来ます。クラスインスタンスの __dict__ 属性とは違って、関数では実際には、 __dict__ に別の辞書を代入出来ます。ですが、新しい値は普通の Python 辞書に制限されています; ズルは 出来ません し、 UserDict インスタンスやなにかほかのマッピングのように振舞うデタラメなオブジェクトはセット出来ません。

参考

PEP 232 - 関数の属性

Barry Warsaw 著、実装

PEP 235: 大文字小文字を区別しないプラットフォームでのモジュールの読み込み

いくつかのオペレーティングシステムは、大小文字区別に無関心なファイルシステムを持っています。MacOS と Windows がその代表例です。それらシステムにおいてはファイル名 FILE.PYfile.py の区別が出来ません。たとえそれが元のファイル名を尊重して格納出来たとしてもです(それらは大小文字維持、でもあります)。

In Python 2.1, the import statement will work to simulate case-sensitivity on case-insensitive platforms. Python will now search for the first case-sensitive match by default, raising an ImportError if no such file is found, so import file will not import a module named FILE.PY. Case-insensitive matching can be requested by setting the PYTHONCASEOK environment variable before starting the Python interpreter.

PEP 217: 対話モード用 Display Hook

When using the Python interpreter interactively, the output of commands is displayed using the built-in repr() function. In Python 2.1, the variable sys.displayhook() can be set to a callable object which will be called instead of repr(). For example, you can set it to a special pretty-printing function:

>>> # Create a recursive data structure
... L = [1,2,3]
>>> L.append(L)
>>> L # Show Python's default output
[1, 2, 3, [...]]
>>> # Use pprint.pprint() as the display function
... import sys, pprint
>>> sys.displayhook = pprint.pprint
>>> L
[1, 2, 3,  <Recursion on list with id=135143996>]
>>>

参考

PEP 217 - Display Hook の対話的な使用

Moshe Zadka 著、実装

PEP 208: 新しい型強制モデル

数値強制が C レベルでどのようになされるかについての修正は、とても大きなものでした。これは Python の C 拡張の著者にのみ影響し、数値操作をサポートする拡張型を書くのをより柔軟にするものです。

拡張型はその PyTypeObject 構造体に、新しい型強制モデルをサポートすることを示すために Py_TPFLAGS_CHECKTYPES フラグをセット出来るようになりました。そのような拡張型内では、数値的スロット関数は 2 つの引数が同じ型であることを仮定しなくなります。代わりに、2 つの引数が異なる型を渡せて、内部的に型変換を実行出来ます。スロット関数にそれが処理出来ない型が渡された場合は、それが失敗であることを表すために Py_NotImplemented シングルトン値への参照を返せます。この場合他の数値関数が試されて、おそらく操作を実行出来ます。それでも Py_NotImplemented を返すなら TypeError が送出されます。Python で書かれた数値メソッドも Py_NotImplemented を返せます。この場合インタプリタはメソッドが存在しないものとして振舞います。 (おそらく TypeError が投げられたり、オブジェクトのほかの数値メソッドが試されます。)

参考

PEP 208 - 型強制モデルの手直し

Neil Schemenauer により著され、実装されましたが、大変多くを Marc-André Lemburg による以前の仕事に拠っています。C レベルで今では数値操作がどのように処理されるようになったかの細かい点を理解したければ、これを読んで下さい。

PEP 241: Pythonソフトウェアパッケージのためのメタデータ

Python ユーザからの日常的な不平は、既にある全ての Python モジュールの単一のカタログがないことです。T. Middleton の http://www.vex.net/parnassus/ にある Vaults of Parnassus が Python モジュールの最小限のカタログとしてありますが、Vaults にソフトウェアを登録することはオプショナルであって、多くの人々はわざわざそれをしません。

この問題をどうにかするための最初の小さな一歩として、Distutils の sdist コマンドを使ってパッケージ化する Python ソフトウェアに PKG-INFO と名付けられたファイルを含むようにしました。これには名前、バージョン、著者 (カタログ化の用語ではメタデータ) のような情報を含んでいます。PEP 241 が PKG-INFO ファイルに持てるフィールドの完全なリストを記述しています。Python 2.1 を使ったソフトウェアをパッケージ化し始めた人々によってパッケージがどんどんメタデータを含み、自動的なカタログ化システムを構築し、それを実験することが出来るようになります。その結果の経験により、おそらく本当に良いカタログを設計出来、Python 2.2 でそのサポートを構築出来るでしょう。例えば Distutils の sdist コマンドと bdist_* コマンド群はあなたのパッケージをカタログサーバに自動的にアップロードする upload オプションをサポート出来るでしょう。

PKG-INFO を含んだパッケージの作成は Python 2.1 を使っていなくても開始することが出来ます。Distutils の新しいリリースが以前のバージョンの Python ユーザ向けにも作られているからです。Distutils のバージョン 1.0.2 が、多数のバグフィックスや拡張とともに、 PEP 241 の変更を含んでいます。これは https://www.python.org/community/sigs/current/distutils-sig/ にある Distutils SIG から入手可能です。

参考

PEP 241 - Pythonソフトウェアパッケージのためのメタデータ

A.M. Kuchling 著、実装

PEP 243 - レポジトリアップロードモジュールのメカニズム

Sean Reifschneider により著されました。このドラフト PEP は中央サーバに Python パッケージをアップロードする機構について提案しています。

新しいモジュールと改良されたモジュール

  • Ka-Ping Yee が 2 つの新規モジュールを寄稿しました: inspect モジュールは、動作中の Python コードについての情報を取得するもので、 pydoc モジュールは docstring を対話的に HTML またはテキストに変換します。オマケとして、 Tools/scripts/pydoc が自動的にインストールされるようになっていて、これは指定した Python モジュール、パッケージ、またはクラス名のドキュメントを pydoc.py を使って出力します。例えば pydoc xml.dom はこのような出力をします:

    Python Library Documentation: package xml.dom in xml
    
    NAME
        xml.dom - W3C Document Object Model implementation for Python.
    
    FILE
        /usr/local/lib/python2.1/xml/dom/__init__.pyc
    
    DESCRIPTION
        The Python mapping of the Document Object Model is documented in the
        Python Library Reference in the section on the xml.dom package.
    
        This package contains the following modules:
          ...
    

    pydoc には TK ベースの対話的ヘルプブラウザも含まれています。 pydoc はすぐに病みつきになります。お試しあれ。

  • 2 つの異なる単体テスト用モジュールが標準ライブラリに追加されました。Tim Peters によって寄稿された doctest モジュールは、docstring 内に埋め込まれた実例を実行することによるテストのフレームワークで、期待の出力と結果を比較します。Steve Purcell の手による PyUnit は JUnit に触発された単体テストフレームワークです。JUnit も Kent Beck の Smalltalk のテストフレームワーク由来です。PyUnit についてのより詳細な情報は http://pyunit.sourceforge.net/ を参照してください。

  • 新規の difflib モジュールは SequenceMatcher クラスを含んでおり、これは 2 つのシーケンスを比較し、一方のシーケンスから他方に変換するのに必要な変更点を計算します。例えば、このモジュールは Unix の diff プログラムに似たツールを書くのに使えます。事実、サンプルプログラム Tools/scripts/ndiff.py が、そのようなスクリプトをどのようにして書くかを実演しています。

  • curses.panel はパネルライブラリへのラッパーであり、ncurses と SYSV curses の一部であり、 Thomas Gellekum により寄稿されました。パネルライブラリは深さ(depth)の追加機能を持つウィンドウを提供しています。ウィンドウは深さ順での高い方、低い方に移動出来、パネルライブラリはパネルがどこで重なるか、区域のどちらが可視かを理解します。

  • PyXML パッケージは Python 2.0 から少しのリリースでいなくなり、Python 2.1 では xml パッケージの更新バージョンを含んでいます。いくつかの特筆すべき変更点には Expat 1.2 以降のバージョンのサポートがあり、Expat パーサで Python でサポートされる任意のエンコーディングのファイルを処理出来るようにし、SAX、DOM、 minidom モジュールについての色々なバグフィックスがあります。

  • Ka-Ping Yee は未捕捉の例外を処理するもうひとつのフックも寄稿しました。 sys.excepthook() には呼び出し可能オブジェクトをセット出来ます。例外がどの try...except にも捕捉されない場合に、例外は sys.excepthook() に通されて、そこで好きなことを何でも出来ます。9 回目の Python カンファレンスにおいて、Ping はこのフックを使ったアプリケーションのデモを行いました。そこでは、スタックフレームを列挙するだけでなくそれぞれのフレームでの関数の引数とローカル変数の列挙も行う拡張トレースバックの表示をしていました。

  • asctime()localtime() のような time モジュールの多くの関数が、エポックからの秒数での浮動小数点数の引数を必要とします。これら関数の最も一般的な使い方は現在時刻とともに用いるものですから、浮動小数点数引数が省略可能となりました。値が与えられなければ現在時刻が使われます。例えばログファイルのエントリは普通現在時刻を含んだ文字列が必要なものですが、Python 2.1 では、以前では長々しい time.asctime(time.localtime(time.time())) と書かなければならなかったものを代わりに time.asctime() とすることが出来ます。

    この変更は Thomas Wouters により提案され、実装されました。

  • ftplib モジュールがデフォルトでパッシブモードでファイルを取得するようになりました。これはパッシブモードがファイアウォール配下ではより良く動作するようだからです。この要望は Debian のバグトラッキングシステムから起こりました。ほかの Debian パッケージがファイル取得に ftplib を使い、ファイアウォールの元で動作しなかったのです。このことが誰かの問題になるとは思えません。Netscape のデフォルトがパッシブモードですし、苦情を言う人々も稀でした。ですがもしもパッシブモードがあなたのアプリケーションやネットワーク構成にとって不適切である場合には、FTP オブジェクトの set_pasv(0) を呼び出して、パッシブモードを無効にしてください。

  • socket モジュールに、Grant Edwards により寄稿された、生のソケットへのアクセスのサポートが追加されました。

  • pstats モジュールに、Python プログラムの時間計測プロファイルを表示する単純な対話的統計ブラウザが含まれるようになり、これはモジュールがスクリプトとして実行された場合に呼び出されます。Eric S. Raymond によって寄稿されました。

  • 実装依存の関数ですが sys._getframe([depth]) が、現在の呼び出しスタックより、指定したフレームオブジェクトを返すものとして追加されました。 sys._getframe() は呼び出しスタックの一番上のフレームを返します。オプショナルな整数引数 depth を与えると、関数はスタックの一番上から下 depth ぶんの呼び出しのフレームを返します。例えば sys._getframe(1) は呼び出し元のフレームオブジェクトを返します。

    この関数は CPython のみに含まれ、 Jython や .NET 実装にはありません。デバッグのためだけに用い、製品コード内にこれを書いてしまう誘惑に打ち克ってください。

その他の変更と修正

短めのリリースサイクルだったため Python 2.1 では比較的少ない変更でした。CVS 変更ログの検索では 117 のパッチ適用と 136 のバグフィックスが見つかります。ともに少なく見積もっています。いくつかの注目に値する変更を紹介します:

  • 特殊化されたオブジェクトアロケータがオプショナルで利用可能になっています。これはシステムの malloc() よりも速くて省メモリであるはずです。このアロケータは C の malloc() 関数を大きなメモリプールを得るのに使い、それより小さなメモリ要求はこれらプールで実現しています。この機能は configure スクリプトに --with-pymalloc オプションを与えることで有効化出来ます。実装の詳細については Objects/obmalloc.c をみてください。

    C 拡張モジュールの作者はこのオブジェクトアロケータを有効にしてテストすべきです。というのもある種の誤ったコードが破壊されて、ランタイムにコアダンプを引き起こしうるからです。Python の C API 内には数多くのメモリアロケーション関数がありますが、これは以前は単に C ライブラリの malloc()free() への別名であり、何かの間違いでミスマッチな関数呼び出しをしても、誤りは気付かれないものでした。今回のこのオブジェクトアロケータを有効化すると、これら関数は malloc()free() への別名ではまったくなくて、メモリ解放に誤った関数を呼び出すとコアダンプし得ます。例えば PyMem_New() を使って獲得したメモリは free() ではなく PyMem_Del() を使って解放する必要があります。Python に含まれるいくつかのモジュールがまさにこれに抵触し、修正の必要がありました。間違いなく多くのサードパーティモジュールが同じ問題を抱えているでしょう。

    オブジェクトアロケータは Vladimir Marangozov により寄稿されました。

  • The speed of line-oriented file I/O has been improved because people often complain about its lack of speed, and because it’s often been used as a naïve benchmark. The readline() method of file objects has therefore been rewritten to be much faster. The exact amount of the speedup will vary from platform to platform depending on how slow the C library’s getc() was, but is around 66%, and potentially much faster on some particular operating systems. Tim Peters did much of the benchmarking and coding for this change, motivated by a discussion in comp.lang.python.

    A new module and method for file objects was also added, contributed by Jeff Epler. The new method, xreadlines(), is similar to the existing xrange() built-in. xreadlines() returns an opaque sequence object that only supports being iterated over, reading a line on every iteration but not reading the entire file into memory as the existing readlines() method does. You’d use it like this:

    for line in sys.stdin.xreadlines():
        # ... do something for each line ...
        ...
    

    For a fuller discussion of the line I/O changes, see the python-dev summary for January 1–15, 2001 at https://mail.python.org/pipermail/python-dev/2001-January/.

  • 辞書に新しくメソッド popitem() が追加されました。これで辞書の内容を破壊的にイテレートすることが出来ます。これは大きな辞書では速くなりえます。全てのキーまたは値を含んだリストを構築する必要がないからです。 D.popitem() は辞書 D からランダムに (key, value) ペアを削除して、その 2 要素タプルを返します。これは Moshe Zadka による示唆と事前のパッチののちに、Tim Peters と Guido van Rossum によりほとんどが実装されました。(—訳注: 速くなる理由の説明が、イテレータもジェネレータもなかった Python 2.1 時点での説明であることに注意してください。—)

  • from module import * を使ってインポートする際にインポートされる名前を制御出来るようになりました。インポートされるべき名前のリストを含む __all__ 属性を定義することでこれを行えます。一つのよくある不平が、 sysstring のように、ほかのモジュールをモジュールがインポートする場合に、 from module import * がインポートしているモジュールの名前空間内にそれらを追加することです。これをフィックスするには、 __all__ に公開名を単に列挙します:

    # List public names
    __all__ = ['Database', 'open']
    

    このパッチのより厳密な版が最初に示唆されて Ben Wolfson により実装されましたが、python-dev でのいくつかの議論を経てからより弱い最終版がチェックインされました。

  • 文字列に repr() を適用するとこれまでは表示出来ない文字について、8 進エスケープが使われていました。例えば改行コードは '\012' でした。これは Python の起源である C に追従した名残ですが、こんにちでは普段使いで 8 進エスケープが使われることは非常に少なくなりました。Ka-Ping Yee が 8 進の代わりに 16 進を使いつつ相応の文字には \n, \t, \r などのエスケープを使うよう示唆し、この新しい書式化を実装しました。

  • コンパイル時点で検出される構文エラーがエラーとなったファイル名と行番号を含む例外を送出できるようになり、またこれによりコンパイラの再編成という喜ばしい副作用がありました。Jeremy Hylton により達成されました。

  • 他のモジュールをインポートする C 拡張が PyImport_ImportModule() を使うように変更されました。これによりインストールされている任意のインポートフックが使われます。これは C コードより他のモジュールをインポートする必要があるサードパーティ拡張にも推奨されます。

  • Unicode 文字データベースのサイズが Fredrik Lundh のおかげでさらに 340K だけ小さくなりました。

  • いくつかの新たなポートの寄与: MacOS X (by Steven Majewski), Cygwin (by Jason Tishler); RISCOS (by Dietmar Schwertberger); Unixware 7 (by Billy G. Allie).

そしてよくあるマイナーなバグフィックス、マイナーなメモリリーク、ドキュメンテーション文字列の編集やほかの微調整があり、全てを列挙するには長過ぎます。もし見たいのであれば、CVS ログで完全な詳細を読んで下さい。

謝辞

著者は提案の申し出や修正、様々なこの記事の草稿の助けをしてくれた以下の人々に感謝します: Graeme Cross, David Goodger, Jay Graves, Michael Hudson, Marc-André Lemburg, Fredrik Lundh, Neil Schemenauer, Thomas Wouters.