What's New in Python 2.0

著者:

A.M. Kuchling and Moshe Zadka

はじめに

新 Python リリース、バージョン 2.0 は、2000 年 10 月 16 日にリリースされました。この記事では 2.0 のエキサイティングな新機能をカバーし、いくつかの有用な変更点をハイライトし、少しの、コードの書き換えを要する互換性のない変更点について指摘します。

Python の開発は、リリースとリリースの間で止まることはなく、バグフィックスと改善はとめどなく、日夜提出されます。多くのマイナーフィックス、少しの最適化、ドキュメンテーション文字列の追加、より良いエラーメッセージが 2.0 に仲間入りしました。これら全てを列挙するのは不可能ですが、それは確かに大事でしょう、全てのリストを見たければ、公に入手可能な CVS ログを調べてください。この前進は、今やバグ修正に日々を費やすことで報酬を受け取って PythonLabs のために働く 5 人の開発者、それと SourceForge に移行した結果改善されたコミュニケーションのおかげです。

Python 1.6 はいかがですか?

Python 1.6 は「推定的義務」の Python リリースと考えることが出来ます。2000 年 5 月にコア開発チームが CNRI を離れたあと、CNRI は Python にかかる作業全てが CNRI で実施されることを含む 1.6 リリースが作成されることをリクエストしました。それゆえ Python 1.6 は、最も重要な新機能としての Unicode サポートを含む、2000 年 5 月の CVS ツリーの状態と同等です。開発はもちろん 5 月以降も継続されましたので、1.6 ツリーは Python 2.0 との前方互換を保障するために少しの修正を受け取りました。1.6 はですから、Python の進化の一部であり、側枝ではありません。

では、あなたは Python 1.6 に興味を示すべきでしょうか? おそらく答えはノーです。1.6final と 2.0beta1 のリリースは同じ日に行われ (2000 年 9 月 5 日)、Python 2.0 のファイナライズはその一ヶ月かそこらで行われるよう計画されました。もしあなたが保守すべきアプリケーションを持っているならば、1.6 への移行には少しばかりコードの破壊を伴うようです。つまりその修正を行い、一ヶ月の間に 2.0 への移行による別の破壊ラウンドがやってきます。直接 2.0 に移行したほうが良いでしょう。このドキュメントに記載する、ほとんどの面白い機能は 2.0 のみのものであり、なぜならほとんどの作業は、5 月から 9 月の間に行われたからなのです。

新しい開発プロセス

Python 2.0 における最も重要な変化はコードに対するものではまったくなくて、Python がどのように開発されるのかについてでしょう: 2000 年 5 月に Python 開発者たちは、ソースコード格納、バグ報告の追跡、パッチ提出の待ち行列管理のための SourceForge によって利用出来るようになったツールの使用を始めました。Python 2.0 ではバグ報告やパッチの提出には、Python プロジェクトページで利用可能なバグトラッキングとパッチ管理ツールを使ってください。 https://sourceforge.net/projects/python/ にあります(訳注: 2015 年現在の状況は What's New in Python 2.6 参照)。

SourceForge で現在ホストされているサービスの中で最も重要なのは Python CVS ツリーで、Python のソースコードを含む、バージョンコントロールされたレポジトリです。以前までは、CVS ツリーへの書き込み許可を持つ人々が 7 人ほどいて、全てのパッチはその中の一人が精査とチェックをする必要がありました。明らかにこれはスケーラブルではありませんでした。CVS ツリーを SourceForge に移動することで、より多くの人々に書き込み許可を与えることが可能になりました; 2000 年 9 月時点で、27 人の人々が変更をチェックイン出来るようになっていました。これは 4 倍の増加です。これは大規模な変更、これまでであれば小さなコア開発グループによるフィルタを経由しなければならないために試みられなかったような、大規模な変更を可能にしています。例えばある日 Peter Schneider-Kamp は K&R C 互換を落としてしまうことを思い立ち、Python の C ソースを ANSI C に変換しました。python-dev メーリングリストでの承認を得たのち、彼は立て続けにチェックインを開始しておよそ一週間ほどで終わらせ、ほかの開発者たちも手助けに参加し、そして作業は完了しました。書き込み許可が 5 人だけだったならば、おそらくそのタスクはこう見做されたでしょう:「素晴らしい。けれども時間と労力に見合わない」。そして決して実現することはなかったことでしょう。

SourceForge のサービスを使うことへのシフトは、開発の目覚しいスピードアップをもたらしました。パッチはいまや、提出され、コメントされ、提出者以外の別人によって改定されて戻ってきて、などなどが、パッチがチェックインの価値があると判断されるまで行われています。バグは唯一つの中央保管庫で追跡され、修正には特定の誰かを割り当てることが出来、そして私たちはオープンバグを進捗の指標として考えることが出来ます。これは代償なしでは達成しませんでした; 開発者には今や以前よりもたくさんの処理すべき電子メールがあり、より多くメーリングリストに追従しなければならず、そして新しい環境のための特別なツールを要しました。例えば、SourceForge はデフォルトでパッチ提出とバグ報告を電子メールで通知しますが、これは全く助けにならないもので、Ka-Ping Yee はもっと有用なメッセージを送信するための HTML スクリーンスクレイパを書きました。

簡単にコードを追加出来るようになったことは、当初少し苦痛を大きくしました。例えばコードが不十分なままだったり、開発グループからのはっきりとした承諾のないままチェックインされたりするといったことです。浮上してきた承認プロセスは、Apache グループが使っているようなものにいくらか似たものです。開発者たちは +1, +0, -0, -1 というふうにパッチに投票できます; +1 と -1 は承諾、却下を表し、+0 と -0 は、開発者は変更にほとんど興味がないけれどもやや肯定、否定の傾向であることを意味します。Apache モデルからの最も大きな違いは、投票行為は本質的に助言であって、優しい終身独裁者 Guido van Rossum 侯に大衆の民意を伝えるものであることです。彼は投票結果をそれでも無視出来ますし、コミュニティが異論を唱えようが変更を承認したり却下したり出来ます。

実際のパッチの作成は新機能の追加での最後のステップであり、通常、良いデザインを工面する前のタスクと容易に比較出来ます。一方で新機能についての議論はしばしばメーリングリストでの長大なスレッドを巻き起こし、議論に追いつくのが大変になり、そして誰も python-dev の投稿全てを読めません。それゆえに、Python 拡張提案 (Python Enhancement Proposals: PEPs)を書く、相対的に形式ばったプロセスが、始動しました。インターネットの RFC をモデルにしたものです。PEPs は新機能提案を記述した草案文書であり、コミュニティの合意として提案が承認されるか却下されるまで継続的に改定されます。 PEP 1 の導入部、"PEP の目的とガイドライン" から引用します:

PEP は Python Enhancement Proposal を意味します。PEP は、Python コミュニティに対して情報を提供する、あるいは Python の新機能について記述する設計文書です。PEP は、機能についての技術的な仕様とその機能の論拠(理論)を簡潔に伝えるべきです。

私たちは PEP が新機能提案にかかる、コミュニティによる問題提起の集積と Python になされる設計決断の文書化のための最上位の機構となることを意図しています。PEP の著者にはコミュニティ内の合意形成を行うこと、反対意見を文書化することの責務があります。

PEP の編集に関するプロセス、様式、体裁についての詳細が PEP 1 の残りの部分に書かれています。PEPs は SourceForge 上の Python CVS ツリーで営まれますが Python 2.0 配布物の一部ではなく、 https://peps.python.org/ で HTML 形式で利用可能です。2000 年 9 月時点で PEP 201 の "Lockstep Iteration" から PEP 225 の "Elementwise/Objectwise Operators" までの 25 の PEP があります。

Unicode 文字列型

Python 2.0 での最大の新機能は新しい基礎データ型、Unicode 文字列です。Unicode は文字を表現するのに ASCII で使用される 8 ビット数の代わりに 16 ビットを使います。これによって 65,536 の個別の文字がサポート出来ます。(---訳注: Unicode の扱いはまず Python 2.2 で UCS4 が使えるように拡張され(つまり 32 ビットに拡張)、Python 3 では Unicode が唯一の文字列型に変更されています。後者の変更点は非常に大きいですが、クックブックの「Python 2 から Python 3 への移植」に比較的よくまとめられています。---)

最終的な Unicode サポートに関するインターフェイスは、python-dev メーリングリストにおける数え切れない、時として嵐のような議論を経て、Fredrik Lundh によって実装された Unicode 文字列型に基づいて、ほとんどが Marc-André Lemburg によって実装されました。インターフェイスについての詳細な説明は PEP 100 「Python Unicode の統合」に記述されました。今ここでは、Unicode インターフェイスについて、一番重要な点を単純にカバーするだけにしましょう。

Python ソースコード内では Unicode 文字列は u"string" のように書きます。任意の Unicode 文字は新しく追加されたエスケープシーケンスで書きます。 \uHHHH のように書き、 HHHH は 0000 から FFFF までの 4 桁の 16 進表記数です。以前からあるエスケープシーケンス \xHH も使えますし、8 進表記も、 \777 で表現される U+01FF までの文字に使えます。

Unicode 文字列は普通の文字列と全く似ていて、 immutable なシーケンス型です。添え字でアクセス出来、スライス出来ますが、インプレイスに変更することは出来ません。Unicode 文字列は encode( [encoding] ) メソッドを持っていて、これは望みのエンコーディングでエンコードした 8 ビット文字列を返します。エンコーディングは文字列で名前付けられていて、例えば 'ascii', 'utf-8', 'iso-8859-1' のようなものです。コーデック API は、新しいエンコーディングを実装し、Python プログラム全体を通して利用可能となるよう登録するために定義されています。エンコーディングが指定されない場合はデフォルトのエンコーディングは普通 7 ビット ASCII ですが、Python インストレーションにおいて、 site.py のカスタマイズ版内で sys.setdefaultencoding(encoding) を呼び出すことで変更出来ます。

8 ビット文字列と Unicode 文字列を結合すると常に、デフォルトの ASCII エンコーディングを使って Unicode に型変換されます。 'a' + u'bc' の結果は u'abc' になります。

新たなビルトイン関数が追加され、既存のビルトイン関数も Unicode サポートのために修正されました:

  • unichr(ch) は Unicode におけるコードが整数 ch になるような文字 1 文字からなる Unicode 文字列を返します。

  • u が 1 文字の通常文字あるいは Unicode 文字として、 ord(u) はコードを整数で返します。

  • unicode(string [, encoding] [, errors] ) は、8 ビット文字列から Unicode 文字列を作ります。 encoding は使用するエンコーディング名の文字列です。 errors パラメータは、現在エンコーディングにおいて不正な文字の扱いを指示します; これに値として 'strict' を渡すと全てのエンコーディングエラーに対し、例外を引き起こします。 'ignore' を渡すとエラーは黙って無視されます。 'replace' を渡すと、全ての問題ケースで、公式な置き換え文字である U+FFFD に置き換えます。

  • exec 文や eval(), getattr(), setattr() のような色々なビルトインも、普通の文字列同様に Unicode 文字列を受け付けるようになりました。(この修正をするプロセスをいくつかのビルトインで忘れている可能性もあります。文字列を受け取るものが Unicode を全く受け取らないビルトインを見つけたら、バグとして報告してください。)

新規モジュール unicodedata は、Unicode 文字の特性へのインターフェイスを提供します。例えば unicodedata.category(u'A') は 2 文字の文字列 'Lu' を返しますが、これは、 'L' が letter を、 'u' が uppercase を表します。 unicodedata.bidirectional(u'\u0660') は 'AN' を返し、これは U+0660 が Arabic Number であることを表します。

codecs モジュールには、既存のエンコーディングをルックアップする関数、新しいエンコーディングを登録する関数が含まれます。新しいエンコーディングを実装したいと思うのでない限りは、一番使うことになるのは codecs.lookup(encoding) でしょう。これは 4 要素のタプルを返します: (encode_func, decode_func, stream_reader, stream_writer) 。

  • encode_func は、Unicode 文字列を受け取って 2 要素タプル (string, length) を返す関数です。 string は、与えられたエンコーディングで Unicode 文字列を変換した部分 (おそらく全体) を含む 8 ビット文字列で、 length は何文字の Unicode 文字列が変換されたかを伝えます。

  • decode_func は encode_func の対となる関数で、8 ビット文字列を受け取って、2 要素のタプル (ustring, length) を返します。 ustring が結果の Unicode 文字列で、整数 length が、8 ビット文字列何文字が消費されたかを表します。

  • stream_reader は、ストリームからの入力のデコードをサポートするクラスです。 stream_reader(file_obj) は read()、readline()、readlines() メソッドを持つオブジェクトを返します。 これらのメソッドはいずれも、指定されたエンコーディングから変換して Unicode 文字列を返します。

  • 同様に、stream_writer はストリームへの出力のエンコードをサポートするクラスです。 stream_writer(file_obj) は write() と writelines() メソッドを持つオブジェクトを返します。 これらのメソッドは Unicode 文字列を受け取り、出力時に指定されたエンコーディングに変換します。

例えば以下のコードは Unicode 文字列を UTF-8 でエンコーディングしてファイルに書きます:

import codecs

unistr = u'\u0660\u2000ab ...'

(UTF8_encode, UTF8_decode,
 UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8')

output = UTF8_streamwriter( open( '/tmp/output', 'wb') )
output.write( unistr )
output.close()

そして以下コードではファイルから UTF-8 で読めます:

input = UTF8_streamreader( open( '/tmp/output', 'rb') )
print repr(input.read())
input.close()

re モジュールでは Unicode 対応した正規表現が利用可能で、これは新しい根底となる SRE なる実装から成り、Secret Labs AB の Fredrik Lundh によって書かれました。

Python コンパイラに全ての文字列リテラルを Unicode 文字列として解釈させるための -U コマンドラインオプションが追加されました。これはあなたの Python コードのテストと将来の保障を意図しています。というのも、将来の Python バージョンでは 8 ビット文字列のサポートがなくなって、Unicode 文字列だけとなる予定だからです。 (---訳注: ここで言っている将来バージョンとは、結果的には Python 3 になりました。What's New での明記はないのですが -U オプションは Python 2.7 時点では存在していません。ですが同じことは 2.6 以降では from __future__ import unicode_literals で出来ます。 ---)

リストの内包表記

リストというのは Python の主要なデータ型で、多くのプログラムがリストをいつかは操るものです。リストの操作での 2 つのよくある操作は、それらについてループし、あるいは特定の基準に合致したものを取り出すか個々の要素にある関数を適用するかする、といったものです。例えば文字列のリストが与えられた場合、特定の部分文字列を含む全ての文字列を引き抜いたり、あるいは各行から末尾の空白を取り除いたりしたいでしょう。

既にあった map() 関数、 filter() 関数がこの目的のためには使えますが、それらにはその引数の一つに関数が必要です。何か既存のビルトイン関数で直接渡せるものがあればよいのですが、これがない場合その必要とされる仕事をする小さな関数を作る必要があって、また、Python のスコープ規則によって、その小さな関数が何かほかの情報を必要とする場合に醜いものになります。前パラグラフでの最初の例を考えましょう。指定の部分文字列を含む文字列リストから全てを探す例です。このように書けるでしょう:

# リスト L から、部分文字列 S を含むすべての文字列の
# リストを作る。
sublist = filter( lambda s, substring=S:
                     string.find(s, substring) != -1,
                  L)

Python のスコープ規則のために、 lambda 式で作っている匿名関数にデフォルト引数を使い、これに検索対象の部分文字列を渡しています。リスト内包表記はこれを明快にします:

sublist = [ s for s in L if string.find(s, S) != -1 ]

リスト内包表記は以下の形式を持ちます:

[ expression for expr in sequence1
             for expr2 in sequence2 ...
             for exprN in sequenceN
             if condition ]

for...in 節はイテレートするシーケンスを含みます。シーケンス群は同じ長さである必要はありません。それらは並列でイテレートされる のではなく 左から右の順で周ります。続くパラグラフでもっとわかりやすく説明します。生成されるリストの要素は一連の expression の値となります。最後の if 節はオプショナルです。これがあれば expression は condition が真の場合にのみ評価・追加されます。

セマンティクスについてとてもわかりやすく説明しておきましょう。リスト内包は以下の Python コードと等価です:

for expr1 in sequence1:
    for expr2 in sequence2:
    ...
        for exprN in sequenceN:
             if (condition):
                  # 式の値を
                  # 結果のリストに
                  # 追加する。

つまり、複数の for...in 節があって if がないときの最終出力は、長さが各シーケンス長の積に等しくなるということです。長さ 3 のリスト二つなら、出力リストの長さは 9 要素です:

seq1 = 'abc'
seq2 = (1,2,3)
>>> [ (x,y) for x in seq1 for y in seq2]
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
('c', 2), ('c', 3)]

Python の文法に曖昧さを紛れ込ませないように、expression でタプルを作るなら括弧で囲わなくてはなりません。下にあるリスト内包表記で、最初のは構文エラーですが、二番目は有効です:

# 構文エラー
[ x,y for x in seq1 for y in seq2]
# 正しい書き方
[ (x,y) for x in seq1 for y in seq2]

リスト内包表記のアイディアは、もともとは関数型プログラミング言語 Haskell (https://www.haskell.org) に由来しています。Greg Ewing が Python にこれを追加することを最も実際的に主張し、彼が最初のリスト内包のパッチを書きました。それは傍目には終わりのない議論が python-dev メーリングリストにて続き、Skip Montanaro によって最新に保たれました。

累算代入 (Augmented Assignment)

累算代入はもう一つの長らく待ち望まれた機能であり、Python 2.0 に追加されました。累算代入演算子には +=, -=, *= などがあります。例えばステートメント a += 2 は変数 a に 2 を加算し、これはちょっとだけ長い記述 a = a + 2 と同じです。

サポートされる代入演算子は +=、-=、*=、/=、%=、**=、&=、|=、^=、>>=、<<= です。 Python のクラスは __iadd__()、__isub__() などの名前のメソッドを定義して、累算代入演算子をオーバーライドできます。 例えば、次の Number クラスは数値を格納し、+= を使って値を増やした新しいインスタンスを作成できます。

class Number:
    def __init__(self, value):
        self.value = value
    def __iadd__(self, increment):
        return Number( self.value + increment)

n = Number(5)
n += 3
print n.value

__iadd__() 特殊メソッドは増分の値を引数として呼び出され、値を適切に変更した新しいインスタンスを返す必要があります。 この戻り値が左辺の変数の新しい値として束縛されます。

累算代入演算子は最初に C 言語で導入されて、 awk, C++, Java, Perl, PHP といった C から派生した言語のほとんどでサポートされています。累算代入のパッチは Thomas Wouters により実装されました。

文字列メソッド

これまで、文字列操作の機能は string モジュールにあり、通常は C で書かれた strop モジュールのフロントエンドになっていました。 Unicode の追加により、strop モジュールには問題が生じました。 8 ビット文字列と Unicode 文字列の両方を受け付けるには、すべての関数を書き直す必要があるためです。 文字列引数を 3 つ受け取る string.replace() などの関数では、組み合わせが 8 通りになり、その分コードも複雑になります。

代わりに、Python 2.0 は問題を文字列型に押し込み、文字列操作機能が 8 ビット文字列と Unicode 文字列の両方のメソッドを通じて利用可能としました。

>>> 'andrew'.capitalize()
'Andrew'
>>> 'hostname'.replace('os', 'linux')
'hlinuxtname'
>>> 'moshe'.find('sh')
2

変わらない一つのこと、華やかなエイプリルフールのジョークではありませんが、それは Python 文字列が immutable だということです。ですので文字列メソッドは新しい文字列を返し、それが操作する文字列を変更しません。

古い string モジュールはまだ後方互換性のために残されますが、それはほとんど新たな文字列メソッドへのフロントエンドとして振舞います。

Two methods which have no parallel in pre-2.0 versions, although they did exist in JPython for quite some time, are startswith() and endswith(). s.startswith(t) is equivalent to s[:len(t)] == t, while s.endswith(t) is equivalent to s[-len(t):] == t.

特に触れておきたいもう一つのメソッドは join() です。 文字列の join() メソッドは、文字列のシーケンスという 1 つの引数を受け取り、従来の string モジュールの string.join() 関数で引数の順番を逆にしたものに相当します。 つまり、s.join(seq) は従来の string.join(seq, s) と同じです。

循環参照のガベージコレクション

Python の C 実装は、ガーベージコレクションの実装に参照カウントを使っています。全ての Python オブジェクトは自身を参照している数を維持していて、参照が作成されたり破壊されたりするカウントを調整しています。参照カウントがゼロになればそのオブジェクトにはもはや到達可能ではありません。あなたはそれにアクセスするためのオブジェクトへの参照を持つ必要がありますが、カウントがゼロならば参照はもはや存在しないということです。

参照カウントはある種望ましい特徴を持っています。それは理解しやすく、実装しやすく、結果としての実装の移植性は高く、かなり高速であり、そして、独自のメモリ処理方式を実装しているようなほかのライブラリと共にでも良く振舞います。参照カウントの主要な問題点は、それが時々、オブジェクトにはもう到達不能であることに気付かないので、結果としてメモリリークを引き起こすことです。これは参照の循環がある場合に発生します。

最も単純な循環について考えてみます。クラスインスタンスが自身への参照を持つ場合です:

instance = SomeClass()
instance.myself = instance

上の例の 2 行のコードが実行された後では、 instance の参照カウントは 2 です。参照の一つ目は 'instance' と名付けられた変数からのもので、もう一つの参照は、インスタンスの myself 属性から来るものです。

このあとに続くコードが del instance だとしたら、何が起こるでしょうか? instance の参照カウントは 1 減るので参照カウントは 1 になります。 myself 属性内の参照はいまだ存在します。けれどもインスタンスはもう Python コードからは到達不能ですから、本来削除出来るはずです。お互いを参照しあうならばいくつものオブジェクトが循環に参加しえるので、結果それら全てのオブジェクトはリークしてしまいます。

Python 2.0 はこの問題を、循環検出アルゴリズムを周期的に実行することによりフィックスします。そのアルゴリズムは、到達不能な循環を探して関係するオブジェクトを削除します。新しく追加された gc モジュールは、ガーベージコレクションを実行する関数、デバッグのための統計情報を取得する関数、コレクタのパラメータを調整する関数を提供します。

循環検出アルゴリズムの実行はいくらかの時間がかかるので、結果として多少の追加的なオーバヘッドがかかるでしょう。2.0 を使って循環のコレクションの経験を積んだのちに、 Python 2.1 では注意深い調整によりオーバヘッドを最小に出来ることが望まれています。今のところパフォーマンスの損失がいかほどなのかは明らかではありません。これはこれのベンチマークがトリッキーであり、プログラムがどれだけの頻度でオブジェクトを構築・破棄するのかに大きく依存するからです。循環の検出は Python コンパイル時に無効に出来ます。もしもあなたが小さな速度のペナルティでさえも許容出来ないであるとか、あるいは循環のコレクションがバギーであることを疑うのであれば、 configure スクリプト実行時に --without-cycle-gc スイッチを与えることでそうすることが出来ます。 (---訳注: Python 2.3 でこの循環参照の GC は必須となり、 --without-cycle-gc 、 --with-cycle-gc での有無効化は撤廃されました。---)

何人かの人々がこの問題に体当たりで取り組み、解決に対する貢献をしました。循環検出アプローチの初期の実装は、Toby Kelsey により書かれました。現在のアルゴリズムは CNRI を訪れている間に Eric Tiedemann によって提案されて、Guido van Rossum と Neil Schemenauer が別々の 2 つの実装を書いて、あとで Neil によって統合されたものです。そこに至るまでにもほかの数多くの人々によって提案がなされました。python-dev メーリングリストの 2000 年 3 月のアーカイブに、これに関するほとんどの議論が含まれています。特にタイトルが "Reference cycle collection for Python" と "Finalization again" のスレッドです。

その他の言語コアの変更

Python 文法とビルトイン関数について、色々マイナーな変更がなされました。影響が広範囲に及ぶものは一つもありませんが、手軽で便利なものです。

言語のマイナー変更

引数のタプルやキーワード引数の辞書を使って関数を呼び出すための便利な構文が追加されました。 Python 1.5 以前では組み込み関数 apply() を使っていました。 apply(f, args, kw) は、引数のタプル args と辞書 kw 内のキーワード引数を渡して関数 f() を呼び出します。 2.0 でも apply() は同じように使えますが、Greg Ewing のパッチにより、f(*args, **kw) という短く分かりやすい書き方で同じことができるようになりました。 これは次の関数定義の構文と対称的です。

def f(*args, **kw):
    # args は位置引数のタプル、
    # kw はキーワード引数の辞書
    ...

print の後に >> file を置くと、ファイル類似オブジェクトに出力できるようになりました。 Unix シェルのリダイレクト演算子と似ています。 以前は、print の便利さや単純さに欠けるファイル類似オブジェクトの write() メソッドを使うか、 sys.stdout に新しい値を代入してから元の値に戻す必要がありました。 標準エラー出力への出力は、次のように書く方がずっと簡単です。

print >> sys.stderr, "Warning: action field not supplied"

import module as name または from module import name as othername という構文を使って、インポートするモジュールの名前をリネーム出来るようになりました。パッチは Thomas Wouters が投稿しました。

% 演算子を使う際に新しい書式化スタイルが利用可能です; '%r' はその引数の repr() を挿入します。これは対称性の検討からも考えられました。今の場合は既存の '%s' が引数の str() を挿入することに呼応するものです。例えば '%r %s' % ('abc', 'abc') は文字列 'abc' abc を返します。

以前は Python の組み込みの in 演算子をオーバーライドして独自の動作を実装するクラスは作れませんでした。 obj in seq は、シーケンス seq に obj があれば真を返します。 Python は obj が見つかるか IndexError が発生するまで、シーケンスの各インデックスを順に調べていました。 Moshe Zadka のパッチにより、in の独自の実装を提供する __contains__() 特殊メソッドが追加されました。 また、C で書かれた新しい組み込みオブジェクトは、シーケンスプロトコルの新しいスロットを通じて in の意味を定義できます。

以前のバージョンの Python では、オブジェクトの削除に再帰するアルゴリズムを使っていました。データ構造が深くネストしている場合、インタプリタが C のスタックを使い果たしてクラッシュしていました。Christian Tismer はこの問題をフィックスする削除ロジックに書き直しました。これに関係する注目すべきものとしては、再帰するオブジェクトの比較が無限再帰してクラッシュしていたのを、Jeremy Hylton が書き直してクラッシュしないようにして、有用な結果を生成するようにしたことです。例えば以下コード:

a = []
b = []
a.append(a)
b.append(b)

この 2 つの再帰的なデータ構造は同型なので、a==b の比較は真を返します。 この実装に至る議論と関連する有用なリンクについては、python-dev メーリングリストの 2000 年 4 月のアーカイブにある "trashcan and PR#7" スレッドを参照してください。 また、比較でも例外を送出できるようになりました。 以前の Python では、ユーザー定義の __cmp__() メソッドでエラーが発生しても、その例外が黙って無視されていたため、cmp(a,b) などの比較演算は常に結果を返していました。

主に ActiveState の Trent Mick によって、Itanium プロセッサー上の 64 ビット Windows への Python の移植作業が進められました。 (紛らわしいことに、Win64 でも sys.platform は依然として 'win32' です。 移植を容易にするため、MS Visual C++ が Itanium 上でもコードを 32 ビットとして扱うようだからです。) PythonWin は Windows CE もサポートしています。 詳しくは https://pythonce.sourceforge.net/ の Python CE のページを参照してください。

新たに対応したプラットフォームには Darwin/MacOS X もあり、Python 2.0 で初期サポートが追加されました。 "configure --with-dyld --with-suffix=.x" を指定すると動的読み込みが動作します。 詳しい手順は Python ソース配布物の README を参照してください。

変数に値が割り当てられる前にローカル変数を参照するコードにおいて、 NameError 例外はよく混乱するものであり、この欠点を軽減する試みがなされました。例えば下に挙げるコードは print 文で 1.5.2 と 2.0 の両方で例外が発生しますが、1.5.2 は NameError 例外が、2.0 では新規の例外 UnboundLocalError が投げられます。 UnboundLocalError は NameError のサブクラスですので NameError が投げられることを想定する既存のコードはそのまま動作するはずです。:

def f():
    print "i=",i
    i = i + 1
f()

2 つの新規例外 TabError と IndentationError が導入されました。これらはともに SyntaxError のサブクラスで、Python コードに不適切なインデントが見つかると送出されます。

ビルトイン関数の変更

新しいビルトイン関数 zip(seq1, seq2, ...) が追加されました。 zip() はタプルのリストを返します。それぞれは、引数のシーケンスのそれぞれの i 番目要素たちを含むタプルです。 zip() と map(None, seq1, seq2) の違いは、 map() はシーケンスが同じ長さを持たない場合に None が埋められるのに対し、 zip() は返すリストの長さを、引数のシーケンスの最も短い長さに切り詰めます。

int() と long() 関数は、第 1 引数が文字列の場合にオプションの base パラメータを受け付けるようになりました。 int('123', 10) は 123 を、int('123', 16) は 291 を返します。 int(123, 16) は "can't convert non-string with explicit base" というメッセージの TypeError 例外を送出します。

sys モジュールに、これまでより詳細なバージョン情報を持つ変数が追加されました。 sys.version_info はタプル (major, minor, micro, level, serial) です。例えば仮に 2.0.1beta1 というバージョンだったとすれば、 sys.version_info は (2, 0, 1, 'beta', 1) となるでしょう。 level は "alpha" や "beta" といった文字列で、最終リリースでは "final" です。(---訳注: Python 2.7 で名前付きタプルになっています。また、その属性名では level ではなく releaselevel です。---)

辞書に少し変わった新しいメソッド setdefault(key, default) が追加されました。 既存の get() メソッドと似ていますが、キーが存在しない場合、setdefault() は get() と同様に default の値を返すだけでなく、 その値を key の値として辞書に挿入します。 したがって、次のコードは以下のように置き換えられます。

if dict.has_key( key ): return dict[key]
else:
    dict[key] = []
    return dict[key]

は、単一の return dict.setdefault(key, []) ステートメントだけで書けます。

再帰の暴走を C のスタックが埋め尽くされてコアダンプしたり GPF (訳注: General Protection Fault) する前に捕捉するために、インタプリタは最大の再帰の深さをセットします。以前まではこの制限は Python コンパイル時点で決めてしまっていましたが、2.0 では最大の再帰の深さは sys.getrecursionlimit() と sys.setrecursionlimit() を使って読み取れ、修正出来ます。このデフォルトは 1000 です。また、当該プラットフォームでのおよその最大値は、新たに追加されたスクリプト Misc/find_recursionlimit.py を実行することで知ることが出来ます。

Python 2.0 への移植

新しい Python リリースは以前のリリースとの互換性を保つために苦心していますし、その記録はかなり良くなされてきました。ですがいくつかの変更に関しては、大抵は大きな誤りであると判明した初期デザインを修正するという理由で、後方互換性を破壊することを必ずしも回避せずに有用性が検討されています。このセクションでは Python 2.0 において、古い Python コードを破壊するかもしれない変更点について列挙します。

最も多くのコードに影響しそうな変更は、一部のメソッドが受け付ける引数を厳密にしたことです。 特に append() や insert() などのリストのメソッドには、複数の引数をタプルとして扱うものがありました。 以前の Python では、L がリストの場合、L.append( 1,2 ) はタプル (1,2) をリストに追加しました。 Python 2.0 では、これは 'append requires exactly 1 argument; 2 given' というメッセージの TypeError 例外を送出します。 修正は簡単で、L.append( (1,2) ) のように括弧をもう一組追加し、両方の値をタプルとして渡すだけです。

以前のこれらのメソッドは、Python の C インターフェースの古い関数で引数を解析していたため、より寛容でした。 2.0 では、現行の引数解析関数 PyArg_ParseTuple() を使うように更新されました。 この関数は分かりやすいエラーメッセージを提供し、複数引数での呼び出しをエラーとして扱います。 どうしても 2.0 を使う必要がありコードを修正できない場合は、Objects/listobject.c を編集してプリプロセッサーシンボル NO_STRICT_LIST_APPEND を定義すれば従来の動作を維持できますが、推奨しません。

socket モジュールのいくつかの関数についてはまだこの方法が許されています。例えば、 socket.connect( ('hostname', 25) ) が正しい形式なのですが、 socket.connect('hostname', 25) も動作します。socket.connect_ex と socket.bind も同じようにおおらかです。2.0alpha1 がそれら関数を厳しくしたのですが、ドキュメントが実際には複数引数を取る形式で誤って書かれたために、多くの人々がその厳しくなったチェックに違反してしまうコードを書いてしまいました。GvR はその変更を、市民たちの反応を受けて元に戻し、 socket モジュールについてはドキュメントは修正されて、複数引数形式は非推奨としてマークするに留められました。将来バージョンの Python においてこれはもう一度厳しく なります 。 (---訳注: What's New からは読み取れませんが少なくとも 2.7 では単一引数でしか渡せません。つまり明示的にタプルにして渡す必要があります。---)

文字列リテラル内の \x エスケープは、正確に 2 桁の 16 進表記文字になりました。以前は 'x' に続く 16 進表記文字全てを消費して最後の 8 ビットを使っていたため、 \x123456 は \x56 と同じでした。

例外 AttributeError と NameError がよりフレンドリなエラーメッセージを持つようになっています。それらのテキストは 'Spam' instance has no attribute 'eggs' や name 'eggs' is not defined のようなものになります。以前まではエラーメッセージは存在しない属性名 eggs だけでしたので、この事実に便乗して書かれたコードは 2.0 では壊れます。

整数と長整数を、より相互に置き換えて使えるようにする作業が行われました。 1.5.2 では Solaris に大きなファイルのサポートが追加され、2 GiB を超えるファイルを読み取れるようになりました。 これに伴い、ファイルオブジェクトの tell() メソッドは通常の整数の代わりに長整数を返すようになりました。 2 つのファイルオフセットの差を求め、その結果をシーケンスの乗算や文字列のスライスに使おうとするコードでは、TypeError が発生していました。 2.0 ではシーケンスの乗算やスライスに長整数を使え、直感的に期待される動作になります。 3L * 'abc' は 'abcabcabc' を、(0,1,2,3)[2L:4L] は (2,3) を返します。 ファイルオブジェクトの seek() メソッドや、% 演算子がサポートする書式 (%d、%i、%x など) のように、以前は整数しか受け付けなかったさまざまな場面でも長整数を使えるようになりました。 例えば、"%d" % 2L**64 は文字列 18446744073709551616 を生成します。

一番微妙な長整数についての変更は、長整数を str() してももはや末尾の 'L' 文字が付かないことです。 repr() では今でも付くのにも関わらずです。 'L' は長整数を普通の整数と全く同じように印字したい多くの人々を悩ませてきました。それを各々自分なりの手段で取り除く必要があったからです。これはもう 2.0 では問題でなくなりましたが、 'L' が付くことをあてにして str(longval)[:-1] とするコードが今度は数値の最後の桁を失ってしまいます。

浮動小数点数の repr() は、str() とは異なる書式化の精度を使うようになりました。 repr() は C の sprintf() に %.17g という書式文字列を使い、str() は従来どおり %.12g を使います。 その結果、数値によっては repr() が str() よりも多くの小数桁を表示する場合があります。 例えば、8.1 は 2 進数では正確に表せないため、repr(8.1) は '8.0999999999999996'、str(8.1) は '8.1' となります。

標準例外をクラスの代わりに文字列にするコマンドラインオプション -X は削除されました。 標準例外は常にクラスになります。 標準例外を含む exceptions モジュールは、Python での実装から Barry Warsaw と Fredrik Lundh が書いた組み込みの C モジュールに置き換えられました。

拡張と埋め込みについての変更

いくつかの変更点については覆いが被されていて、C 拡張モジュールや大きなアプリケーションでの Python インタプリタの埋め込みを書く人々からしか見えないものです。Python C API を扱う必要がないのであれば、このセクションは読み飛ばして差し支えありません。

Python C API のバージョン番号がインクリメントされたので、1.5.2 でコンパイルされた C 拡張は 2.0 で動作させるために再コンパイルしなければなりません。Windows では Python 1.5.x でビルドされたサードパーティ拡張を Python 2.0 でインポートすることは、Windows の DLL の仕組みのために、出来ません。その場合 Python は例外を投げ、インポートは失敗します。(---訳注: この文章、おかしなことを言っているので一応…。おそらく「Windows の一般市民は C コンパイラを持っていない」ことが著者の頭にあって、手が滑っているのだと思います。DLL の動作の仕組みが問題となるのは事実ですが、本質的には Windows 云々はあまり関係ないです。API が変わるか ABI が変わるならプラットフォームに関係なくリコンパイルは常に必要です。 ---)

Jim Fulton の ExtensionClass モジュールの利用者に朗報です。 フックの追加により、isinstance() と issubclass() が ExtensionClass をサポートするようになりました。 これで if type(obj) == myExtensionClass のように書く必要はなくなり、より自然な if isinstance(obj, myExtensionClass) を使えます。

Python/importdl.c ファイルが多くの異なるプラットフォームの動的ロードをサポートするのに大量の #ifdef だらけになっていたのを、Greg Stein が掃除して再編成しました。 importdl.c は今ではとても小さくなり、プラットフォーム依存のコードは Python/dynload_*.c ファイル群の束にそれぞれ移動しました。もう一つの掃除。include/ ディレクトリ内で色々な移植性のためのハックを施すためのたくさんの my*.h ファイルたちが、単一の Include/pyport.h にマージされました。

Vladimir Marangozov の手による、待ち望まれた malloc の再編成が完了しました。これは Python インタプリタが C 標準の malloc() の代わりにカスタムアロケータを使うことを容易にするものです。ドキュメントについては Include/pymem.h と Include/objimpl.h のコメントを読んで下さい。インターフェイスが決着するまでの間の長い長い議論については python.org の 'patches' と 'python-dev' リストのウェブアーカイブをみてください。(---訳注: この件についての続きの話が What's New in Python 2.3 に Pymalloc として少しわかりやすく記述されています。---)

MacOS の GUSI 開発環境の最近のバージョンは POSIX スレッドをサポートしています。ですので Python の POSIX スレッディングのサポートは今では Macintosh で動作します。ユーザ空間での GNU pth ライブラリを使ったスレッディングサポートも寄稿されました。

Windows でのスレッディングサポートも拡張されました。Windows は、競合があるケースでのみカーネルオブジェクトを使うスレッドロックをサポートしています。競合がない普通のケースではそれらはより単純な関数を使い、これは段違いに高速です。NT での Python 1.5.2 版でスレッド化すると、非スレッド版の 2 倍遅くなりますが、2.0 に変えるとその差はたった 10% です。これらの改善は Yakov Markovitch の貢献によるものです。

Python 2.0 のソースが ANSI C プロトタイプだけを使うようになったので、Python のコンパイルには ANSI C コンパイラが必須になりました。K&R C しかサポートしないコンパイラではもうコンパイル出来ません。

以前の Python 仮想マシンはバイトコードに 16 ビットの数値を使っており、ソースファイルの大きさに制限がありました。 特に Python ソース内のリストや辞書のリテラルの最大サイズに影響し、Python コードを生成する人がこの制限に遭遇することがありました。 Charles G. Waldman のパッチにより、上限は 2**16 から 2**32 に引き上げられました。

モジュールの初期化時にモジュールの辞書へ定数を追加するための便利な関数が 3 つ追加されました。 PyModule_AddObject()、PyModule_AddIntConstant()、PyModule_AddStringConstant() です。 各関数は、モジュールオブジェクト、追加する名前を含むヌル終端の C 文字列、その名前に代入する値を表す第 3 引数を受け取ります。 第 3 引数は、それぞれ Python オブジェクト、C の long、C の文字列です。

Unix スタイルのシグナルハンドラへのラッパーAPIが追加されました。 PyOS_getsig() でシグナルハンドラを取得し、 PyOS_setsig() で新しいハンドラをセットします。

Distutils: モジュールの簡単インストール

Python 2.0 以前は、モジュールのインストールは退屈な作業でした -- Python がどこにインストールされているかや拡張モジュールのコンパイルに必要なオプションを自動的に知る方法はありませんでした。ソフトウェアの作者は Makefile と設定ファイル群の編集という大変な労力を要する儀式を通過しなければならないのに、それは実際には Unix だけのためであって Windows と MacOS のサポートを置き去りにするものでした。Python ユーザは全く異なったインストール命令に直面していました。それは拡張パッケージごとに異なり、Python インストールをある種つまらない作業としていました。

Greg Ward が率いる配布ユーティリティの SIG は、パッケージのインストールを大幅に簡単にするシステム Distutils を作成しました。 これは Python の標準ライブラリに新たに加わった distutils パッケージを構成します。 うまくいけば、Python モジュールをソースからインストールする手順はどれも同じになります。 まず tarball や zip アーカイブを展開し、python setup.py install を実行するだけです。 プラットフォームとコンパイラーは自動的に検出され、C 拡張モジュールがコンパイルされて、配布物が適切なディレクトリにインストールされます。 オプションのコマンドライン引数でインストール処理を細かく制御できます。 distutils パッケージには、ビルドとインストールの分離、デフォルト以外のディレクトリでのビルドやインストールなど、デフォルトの動作を変更できる箇所が多数あります。

Distutils を使うには setup.py スクリプトを書く必要があります。単純なケースでは、ソフトウェアが .py ファイルだけを含む場合、最小限の setup.py は数行足らずで書けます:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       py_modules = ["module1", "module2"])

setup.py ファイルは、ソフトウェアが少しのパッケージで構成される場合はこれより大きく複雑になることはありません:

from distutils.core import setup
setup (name = "foo", version = "1.0",
       packages = ["package", "package.subpackage"])

C 拡張が最も複雑なケースになりえます。以下は PyXML パッケージからもってきた例です:

from distutils.core import setup, Extension

expat_extension = Extension('xml.parsers.pyexpat',
     define_macros = [('XML_NS', None)],
     include_dirs = [ 'extensions/expat/xmltok',
                      'extensions/expat/xmlparse' ],
     sources = [ 'extensions/pyexpat.c',
                 'extensions/expat/xmltok/xmltok.c',
                 'extensions/expat/xmltok/xmlrole.c', ]
       )
setup (name = "PyXML", version = "0.5.4",
       ext_modules =[ expat_extension ] )

Distutils ではソース配布物、バイナリ配布物の作成の面倒もみてくれます。 "sdist" コマンドは "python setup.py sdist" を実行することで起動し、これは foo-1.0.tar.gz のようなソース配布物を作ります。新しいコマンドを作るのは難しくありません。コマンド "bdist_rpm" と "bdist_wininst" が既に寄稿されていて、各々 RPM 配布物の作成、Windows インストーラの作成を行います。Debian パッケージや Solaris の .pkg のようなほかの配布フォーマットを作成するコマンドについての開発ステージは様々です。

これら全ては、 Python ドキュメントの基本的なセットとして追加されたマニュアル Python モジュールの配布 にドキュメントされています。

XML モジュール

Python 1.5.2 には、Sjoerd Mullender が貢献した xmllib モジュールという簡単な XML パーサーが含まれていました。 1.5.2 のリリース以降、XML 処理のための 2 種類のインターフェースが広く使われるようになりました。 SAX2 (Simple API for XML のバージョン 2) は xmllib と似た点のあるイベント駆動のインターフェースを提供します。 DOM (Document Object Model) は XML 文書を走査や変更が可能なノードのツリーに変換する、ツリーに基づいたインターフェースです。 Python 2.0 では xml パッケージの一部として、SAX2 インターフェースと機能を絞った DOM インターフェースが含まれています。 ここでは、これらの新しいインターフェースの概要を紹介します。 詳しくは Python のドキュメントまたはソースコードを参照してください。 Python XML SIG もドキュメントの改善に取り組んでいます。

SAX2 サポート

SAX は XML を解析するためのイベント駆動のインターフェースを定義します。 SAX を使うには SAX ハンドラークラスを作成する必要があります。 ハンドラークラスは SAX が提供するクラスを継承し、XML パーサーから呼び出される各種メソッドをオーバーライドします。 例えば、パーサーが開始タグや終了タグに遭遇するたびに startElement() と endElement() が呼び出され、 文字データのまとまりごとに characters() が呼び出されます。

イベントドリブンのアプローチはドキュメント全体をいっときにメモリに持たなくて良い点で有利であり、ドキュメントが本当に巨大であるものを処理する際にはこれは重要です。ですが SAX ハンドラクラスを記述することは、ドキュメント構造を変更しようとする場合にはある種入り組んだものとなって、とても複雑になりえます。

以下の小さな実例プログラムでは、全ての開始・終了タグでメッセージを印字するハンドラを定義して、ファイル hamlet.xml をそのハンドラを使ってパースしています:

from xml import sax

class SimpleHandler(sax.ContentHandler):
    def startElement(self, name, attrs):
        print 'Start of element:', name, attrs.keys()

    def endElement(self, name):
        print 'End of element:', name

# パーサーオブジェクトを作成
parser = sax.make_parser()

# 使用するハンドラーを指定
handler = SimpleHandler()
parser.setContentHandler( handler )

# ファイルを解析
parser.parse( 'hamlet.xml' )

詳しくは Python のドキュメント、または https://pyxml.sourceforge.net/topics/howto/xml-howto.html の XML HOWTO を参照してください。

DOM サポート

Document Object Model は XML 文書をツリーで表現するものです。 最上位の Document インスタンスがツリーの根となり、最上位の Element インスタンスを唯一の子として持ちます。 この Element は文字データや子要素を表す子ノードを持ち、それらにもさらに子があるという形で続きます。 DOM を使うと、このツリーを自由な順序で走査し、要素や属性の値にアクセスし、ノードを挿入・削除して、ツリーを XML に戻せます。

DOM は XML ドキュメントを修正するのに有用です。というのも DOM ツリーは作成出来、新規ノードを追加したりサブツリーを再編成したりすることで修正出来、出力として新たな XML ドキュメントを生成出来るからです。DOM ツリーを手動で構築して XML に変換することも出来ます。これにより単純に <tag1>...</tag1> をファイルに書くよりも柔軟性の高い方法で XML 出力を生成出来ます。

Python に同梱されている DOM 実装は xml.dom.minidom モジュールにあります。 XML 名前空間をサポートする、Level 1 DOM の軽量な実装です。 DOM ツリーを生成するための便利な関数 parse() と parseString() が用意されています。

from xml.dom import minidom
doc = minidom.parse('hamlet.xml')

doc は Document のインスタンスです。 Document は、Element や Text など他の DOM クラスと同様、基底クラス Node のサブクラスです。 そのため DOM ツリーのすべてのノードは、自分と子ノードの XML 表現を含む文字列を返す toxml() など、共通のメソッドをサポートしています。 各クラスには独自のメソッドもあります。 例えば、Element と Document のインスタンスには、指定したタグ名を持つ子要素をすべて見つけるメソッドがあります。 先ほどの 2 行の例に続けると、次のようになります。

perslist = doc.getElementsByTagName( 'PERSONA' )
print perslist[0].toxml()
print perslist[1].toxml()

Hamlet XML ファイルに対して上の例は以下のような出力をします:

<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>

ドキュメントのルートエレメントは doc.documentElement として取得出来、その子は簡単に、ノードを削除したり追加したりすることで修正出来ます:

root = doc.documentElement

# Remove the first child
root.removeChild( root.childNodes[0] )

# Move the new first child to the end
root.appendChild( root.childNodes[0] )

# Insert the new first child (originally,
# the third child) before the 20th child.
root.insertBefore( root.childNodes[0], root.childNodes[20] )

各種 Node クラスとそのメソッドの完全な一覧についても、Python のドキュメントを参照してください。

PyXML との関係

XML Special Interest Group は、しばらく前から XML 関連の Python コードに取り組んできました。 PyXML という名前のコード配布物は、SIG のウェブページ https://www.python.org/community/sigs/current/xml-sig から入手できます。 PyXML 配布物も xml というパッケージ名を使っていました。 PyXML を使うプログラムを書いたことがある方は、2.0 の xml パッケージとの互換性が気になるでしょう。

結論として、Python 2.0 の xml パッケージは PyXML と互換性がありません。ですが、直近バージョンの PyXML をインストールすることで互換性を持たせることができます。 多くのアプリケーションは Python 2.0 に含まれる XML サポートで十分ですが、より複雑なアプリケーションは完全なPyXML パッケージをインストールする必要があります。 インストールされた PyXML バージョン 0.6.0 以上は、Python に同梱されている xml パッケージを置き換え、標準パッケージの厳密なスーパーセットとなり、多くの追加機能が追加されます。 PyXML の追加機能には次のようなものがあります。

  • FourThought, Inc. による完全な DOM 実装、4DOM。

  • Lars Marius Garshol が書いた妥当性検証パーサー xmlproc。

  • Fredrik Lundh が書いたパーサーの高速化モジュール sgmlop。

更新されたモジュール

Python の豊富な標準ライブラリには、多くの改善とバグ修正が行われました。 対象には readline、ConfigParser、cgi、calendar、posix、readline、xmllib、aifc、chunk、wave、random、shelve、nntplib などがあります。 各パッチの詳しい内容は CVS のログを参照してください。

Brian Gallew は socket モジュールに OpenSSL のサポートを追加しました。 OpenSSL は、ソケット経由で送信するデータを暗号化する Secure Socket Layer の実装です。 Python のコンパイル時に Modules/Setup を編集して SSL サポートを含めると、socket モジュールに socket.ssl(socket, keyfile, certfile) という関数が追加されます。 これはソケットオブジェクトを受け取り、SSL ソケットを返します。 httplib と urllib モジュールも https:// URL をサポートするよう変更されましたが、SSL 上の FTP や SMTP はまだ実装されていません。

httplib モジュールは HTTP/1.1 をサポートするために Greg Stein によって書き直されました。

httplib の 1.5 版との後方互換性は提供されますが、パイプライン処理など HTTP/1.1 の機能を使うには、別のインターフェースを使うようにコードを書き直す必要があります。

Tkinter モジュールは Tcl/Tk のバージョン 8.1、8.2、8.3 をサポートするようになり、古い 7.x のサポートは終了しました。 Tkinter モジュールでは Tk ウィジェットに Unicode 文字列を表示できるようになりました。 また、Fredrik Lundh による最適化で、特に多数の座標を使う場合に create_line や create_polygon などの操作が大幅に高速化しました。

curses モジュールが、Oliver Andrich による拡張版をもとに大規模に拡張され、ncurses と SYSV curses からの多くの追加機能、例えば色付きの表示、別の文字集合サポート、パッド、マウスサポートなどをサポートするようになりました。このことは、モジュールが BSD curses だけしか持っていない OS とは互換性が無いことを意味しますが、現在メンテナンスされている OS でそういう類のものは無さそうです。

2.0 の Unicode サポートについて前述したように、 re モジュールで提供される正規表現の根底となる実装が変更されました。SRE は新しい正規表現エンジンで、Fredrik Lundh によって書かれ、部分的に Hewlett Packard 社により寄贈されました。これは 8 ビット文字列と Unicode 文字列両方に合致するようサポートされています。

新しいモジュール

数多くのモジュールが新しく追加されました。ここではそれらを短い説明とともに列挙するだけにします。特定のモジュールの詳細は 2.0 のドキュメントを調べてください。

  • atexit: Python インタプリタが終了する前に呼び出す関数を登録します。これまで sys.exitfunc に直接セットしてきたコードは atexit モジュールを代わりに用いるように修正してください。 atexit をインポートし、 atexit.register() で終了時に呼び出す関数を登録します。(Contributed by Skip Montanaro.)

  • codecs、encodings、unicodedata: 新しい Unicode サポートの一部として追加されました。

  • filecmp: 非推奨となった従来の cmp、cmpcache、dircmp モジュールに取って代わるものです。 (Gordon MacMillan と Moshe Zadka が貢献しました。)

  • gettext: このモジュールは Python プログラムに、GNU gettext メッセージカタログライブラリへのインターフェイスを提供することで国際化 (I18N=internationalization) と地域化 (L10N=localization) サポートをもたらします。 (Integrated by Barry Warsaw, from separate contributions by Martin von Löwis, Peter Funk, and James Henstridge.)

  • linuxaudiodev: Linux の /dev/audio デバイスをサポートする、既存の sunaudiodev モジュールに相当するものです。 (Peter Bosch が貢献し、Jeremy Hylton が修正しました。)

  • mmap: Windows、Unix 両方でのメモリマップドファイルへのインターフェイスです。ファイル内容をメモリに直接マッピング出来、それは mutable な文字列であるかのように振る舞い、これにより読み書き出来ます。それらは例えば re モジュールのような普通は文字列を期待するような関数にさえも渡せます。(Contributed by Sam Rushing, with some extensions by A.M. Kuchling.)

  • pyexpat: Expat XML パーサーへのインターフェースです。 (Paul Prescod が貢献しました。)

  • robotparser: ウェブサイトの特定の領域を適切に避けるウェブスパイダーを書くために使う robots.txt ファイルを解析します。 このパーサーは robots.txt ファイルの内容を受け取って規則の集合を作成し、指定した URL を取得してよいかどうかを判定できます。 (Skip Montanaro が貢献しました。)

  • tabnanny: Python ソースコードが曖昧なインデントになっていないかをチェックするモジュール/スクリプトです。 (Contributed by Tim Peters.)

  • UserString: 文字列のように振る舞うオブジェクトを派生させるために便利な基底クラスです。

  • webbrowser: 指定した URL で、プラットフォームに依存しない方法でウェブブラウザを起動するモジュールです。個々のプラットフォームにおいて様々なブラウザが特定の順序で試されます。ユーザはどのブラウザを起動するかを環境変数 BROWSER をセットすることで変更出来ます。(元々は Eric S. Raymond による urllib への、同じ機能追加をするパッチに触発されましたが、最終的なモジュールは Fred Drake が元々 Tools/idle/BrowserControl.py として実装したものに由来し、Fred が標準ライブラリに適合させました。)

  • _winreg: Windows レジストリへのインターフェースです。 _winreg は 1995 年から PythonWin に含まれていた関数を適応したもので、今回コアの配布物に追加され、Unicode をサポートするよう拡張されました。 _winreg は Bill Tutt と Mark Hammond が書きました。

  • zipfile: ZIP 形式アーカイブの読み書きのためのモジュールです。DOS/Windows での PKZIP や Unix での zip により生成されるアーカイブで、 gzip 形式とは混同しないで下さい (こちらは gzip モジュールによってサポートされています)。(Contributed by James C. Ahlstrom.)

  • imputil: 既存の ihooks モジュールより簡単に、独自のインポートフックを書けるモジュールです。 (Greg Stein が実装し、その過程で python-dev 上で多くの議論が行われました。)

IDLE の改善

IDLE は公式の Python のクロスプラットフォームな IDE で、 Tkinter を使って書かれています。Python 2.0 では IDLE 0.6 を含めました。これは多くの新機能追加と改善がなされています。以下はその一部です:

  • UI の、特にシンタックスハイライトと自動インデントの領域において、改善と最適化がなされました。

  • クラスブラウザで、例えばモジュール内のトップレベル関数のような、より多くの情報をみることが出来るようになりました。

  • タブ幅をユーザ制御出来るようになりました。既存の Python ファイルを操作する際には、IDLE は自動的にインデントの慣習を検知してそれに合わせます。

  • 色々なプラットフォームでブラウザの呼び出しがサポートされています。これを使って、ブラウザで Python ドキュメントを開きます。

  • IDLE がコマンドラインを持つようになりました。これは普通の Python インタプリタに大きく似せてあります。

  • 色々な場所でコンテキストヘルプが出るようになっています。

  • IDLE は今ではパッケージとしてインストール出来ます。

  • エディタウィンドウ内では、下部に行/桁を表示するようになっています。

  • 新たな 3 つのキーストロークコマンド: モジュールのチェック (Alt-F5)、モジュールのインポート (F5)、スクリプト実行 (Ctrl-F5).

削除されたモジュール、非推奨となったモジュール

古くなったり、同じことをするためのよりよい方法ができたりしたため、いくつかのモジュールが削除されました。 stdwin モジュールは削除されました。 これは、開発が終了したプラットフォーム非依存のウィンドウツールキット用のモジュールでした。

いくつかのモジュールが lib-old サブディレクトリに移動しました。 cmp、cmpcache、dircmp、dump、find、grep、packmail、poly、util、whatsound、zmod です。 lib-old に移動したモジュールに依存するコードがある場合、そのディレクトリを sys.path に追加すれば再び使えるようになりますが、これらのモジュールを使うコードの更新をお勧めします。

謝辞

著者は提案の申し出や修正、様々なこの記事の草稿の助けをしてくれた以下の人々に感謝します: David Bolen, Mark Hammond, Gregg Hauser, Jeremy Hylton, Fredrik Lundh, Detlef Lannert, Aahz Maruch, Skip Montanaro, Vladimir Marangozov, Tobias Polzin, Guido van Rossum, Neil Schemenauer, and Russ Schmidt.