What's New in Python 2.1

著者:

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):
    "name と等しい項目のリストを返す"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    return L

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

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

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

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

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

x = 1
def f():
    # 次の行は構文エラー
    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 < B は A.__lt__(B) を呼び出します。

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

The built-in cmp(A,B) function can use the rich comparison machinery, and now accepts an optional argument specifying which comparison operation to use; this is given as one of the strings "<", "<=", ">", ">=", "==", or "!=". If called without the optional third argument, cmp() will only return -1, 0, or +1 as in previous versions of Python; otherwise it will call the appropriate method and can return any Python object.

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 モジュールを追加します。サードパーティーのモジュールはまた、彼らがサポート対象外にしたい古い機能を非推奨と知らしめるのにこのフレームワークを利用できます。

例えば、Python 2.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) の結果を、その関数の引数と結果を辞書に格納することでキャッシュするメモライジング関数を考えてみましょう。

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

    retval = f(x)

    # 返されたオブジェクトをキャッシュ
    _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 obj is not None: return obj

    retval = f(x)

    # 弱参照をキャッシュ
    _cache[x] = weakref.ref(retval)

    return retval

weakref モジュールでは、弱参照のように振る舞うプロキシオブジェクトも作成できます。 プロキシオブジェクトからしか参照されていないオブジェクトは解放されます。 ただし、オブジェクトを取得するための明示的な呼び出しは不要で、参照先が存在する間はプロキシがすべての操作を透過的にそのオブジェクトに転送します。 オブジェクトが解放された後にプロキシを使おうとすると、weakref.ReferenceError 例外が送出されます。

proxy = weakref.proxy(obj)
proxy.attr   # obj.attr と同じ
proxy.meth() # obj.meth() と同じ
del obj
proxy.attr   # weakref.ReferenceError を送出

参考

PEP 205 - 弱参照

Fred L. Drake, Jr. 著、実装

PEP 232: 関数の属性

Python 2.1 では、関数に任意の情報を付加できるようになりました。 関数に情報を付加する唯一の手段が __doc__ 属性だったため、関数やメソッドに関する情報を docstring に格納することがよくありました。 例えば、ウェブアプリケーションサーバー 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.PY と file.py の区別が出来ません。たとえそれが元のファイル名を尊重して格納出来たとしてもです(それらは大小文字維持、でもあります)。

Python 2.1 では import 文が、case-insensitive (大小文字に無関心)なプラットフォームで case-sensitivity (大小文字への繊細さ)をシミュレートして動作します。Python は今や、まずはデフォルトで case-sensitive なマッチによる検索をし、それで見つからなければ ImportError を投げます。ですから import file は FILE.PY をインポートしません。case-insensitive マッチングは Python インタプリタ開始前に環境変数 PYTHONCASEOK をセットすることで要求出来ます。

PEP 217: 対話モード用 Display Hook

Python インタプリタを対話的に使う際には、コマンドの出力結果表示にはビルトインの repr() 関数が使われます。Python 2.1 ではこの repr() の代わりに呼び出される呼び出し可能オブジェクトを、 sys.displayhook() 変数にセット出来ます。たとえば特別な pretty- printing 関数をセット出来ます:

>>> # 再帰的なデータ構造を作成
... L = [1,2,3]
>>> L.append(L)
>>> L # Python のデフォルトの出力を表示
[1, 2, 3, [...]]
>>> # 表示用の関数として pprint.pprint() を使う
... 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's の www.vex.net/parnassus/ にあった Vaults of Parnassus (2009年2月に停止、Internet Archive Wayback Machine で閲覧可) が最大のものでしたが、ソフトウェアの登録は任意だったため、多くの人は登録しませんでした。

この問題をどうにかするための最初の小さな一歩として、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 つの新しいモジュールを追加しました。 実行中の Python コードについての情報を取得する inspect.py と、docstring を対話的に HTML やテキストに変換する pydoc.py です。 さらに、自動的にインストールされるようになった 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 について詳しくは https://pyunit.sourceforge.net/ を参照してください。

  • difflib モジュールには、2 つのシーケンスを比較し、一方をもう一方に変換するために必要な変更を計算する SequenceMatcher クラスがあります。 例えば、このモジュールを使って Unix の diff プログラムに似たツールを書けます。 実際に、サンプルプログラム Tools/scripts/ndiff.py はそのようなスクリプトの書き方を示しています。

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

  • Python 2.0 以降、PyXML パッケージは何度かリリースされ、Python 2.1 には更新された xml パッケージが含まれています。 主な変更には、Expat 1.2 以降のサポート、Python がサポートする任意のエンコーディングのファイルを Expat パーサーで処理する機能、SAX、DOM、minidom モジュールのさまざまなバグ修正があります。

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

  • time モジュールの asctime() や localtime() などの関数には、エポックからの経過秒数を表す浮動小数点数の引数が必要でした。 これらの関数は現在時刻を扱うために使われることが最も多いため、この引数は省略可能になりました。 値を指定しなければ現在時刻を使います。 例えば、ログファイルのエントリーには現在時刻の文字列がよく必要になります。 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 により寄稿されました。

  • 行単位のファイル入出力は、遅さを指摘されることが多く、単純なベンチマークにもよく使われるため、高速化されました。 ファイルオブジェクトの readline() メソッドが書き直され、大幅に高速になりました。 高速化の程度は C ライブラリの getc() の遅さに左右されるためプラットフォームごとに異なりますが、およそ 66% で、特定のオペレーティングシステムではさらに大きな改善も見込まれます。 comp.lang.python での議論をきっかけに、Tim Peters がベンチマークと実装の大部分を担当しました。

    Jeff Epler の貢献により、新しいモジュールとファイルオブジェクトのメソッドも追加されました。 新しいメソッド xreadlines() は、既存の組み込み関数 xrange() に似ています。 xreadlines() は、反復処理だけをサポートする不透明なシーケンスオブジェクトを返します。 反復のたびに 1 行を読み取り、既存の readlines() メソッドのようにファイル全体をメモリに読み込むことはありません。 次のように使います。

    for line in sys.stdin.xreadlines():
        # ... 各行を処理する ...
        ...
    

    ライン I/O の変更についての詳しい説明は、 https://mail.python.org/pipermail/python-dev/2001-January/ にある 2001 年 1 月 1--15 日の python-dev のまとめをご覧ください。

  • 辞書に popitem() メソッドが追加され、内容を削除しながら反復処理できるようになりました。 すべてのキーや値を含むリストを作成する必要がないため、大きな辞書では高速になる可能性があります。 D.popitem() は辞書 D から任意の (key, value) の組を削除し、要素数 2 のタプルとして返します。 Moshe Zadka の提案と最初のパッチを受け、主に Tim Peters と Guido van Rossum が実装しました。

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

    # 公開する名前を列挙
    __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.