# 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://www.python.org/dev/peps/ で 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 進表記数です。以前からあるエスケープシーケンス `\xHHHH` も使えますし、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 のスコープ規則によって、その小さな関数が何かほかの情報を必要とする場合に醜いものになります。前パラグラフでの最初の例を考えましょう。指定の部分文字列を含む文字列リストから全てを探す例です。このように書けるでしょう:

    # Given the list L, make a list of all strings
    # containing the substring 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):
                      # Append the value of
                      # the expression to the
                      # resulting list.

つまり、複数の `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 でタプルを作るなら括弧で囲わなくてはなりません。下にあるリスト内包表記で、最初のは構文エラーですが、二番目は有効です:

    # Syntax error
    [ x,y for x in seq1 for y in seq2]
    # Correct
    [ (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` へのフロントエンドでした。 `strop` モジュールへの Unicode サポートの追加には困難がありました。8 ビット文字列と Unicode 文字列を受け付けるために全て書き直す必要があったからです。 `string.replace()` のような関数は、これは 3 つの文字列引数を取るのであって、このことは 8 通りの可能な組合せがあるということで、それに応じてコードが複雑化するものでした。

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

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

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

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

2.0 以前のバージョンでは共通で相当するものがなくて JPython にはかなり暫くの間存在していたのが、2 つのメソッド `startswith()` と `endswith()` です。 `s.startswith(t)` は `s[:len(t)] == t` と等価、 `s.endswith(t)` は `s[-len(t):] == t` と等価です。

特筆しなければならないもう一つ別のメソッドには `join()` があります。文字列の `join()` メソッドは文字列のシーケンスを一つのパラメータとして受け取りますが、これは古い `string` モジュールの `string.join()` と引数が逆ですが同じです。つまり `s.join(seq)` と旧式 `string.join(seq, s)` が同じです。(---訳注: 「引数が逆」はここだけ読むとわかりにくいかもしれません。string モジュールから文字列メソッドへ置き換えるのにほかは第一引数が self に置き換わっただけにみえるのに対しこれはそうではない、ということです。---)

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

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()` を呼び出します。 `apply()` は 2.0 でも同じですが、Greg Ewing によるパッチのおかげで、同じ効果を得るのにより短くてわかりやすい `f(*args, **kw)` が使えます。この構文は以下のような関数定義に呼応するものです:

    def f(*args, **kw):
        # args is a tuple of positional args,
        # kw is a dictionary of keyword args
        ...

`print` 文がUnix シェルのリダイレクト操作のように、 `print` に続けて `>> file` と書くことでその出力をファイルのように振舞うオブジェクトに向けられるようになりました。(---訳注: 念のため。Python 3 では print は文ではなく関数になっており、これは移植性がありません。Python 2.6 以降であれば関数版の print を使う(PEP 3105)か、ファイルオブジェクト自身のメソッドを使ってください。もしくは目的がログ出力であるならば、 `logging` パッケージの使用を検討してください。---) 以前までは次のいずれかをする必要がありました。一つにはファイルのように振舞うオブジェクトの `write()` メソッドを呼び出すことであり、これは `print` が持つ便利さと単純さに欠けています。もう一つは `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)

これに対して比較 `a==b` は、2つの再帰データ構造が同型であるので真を返します (---訳注: 詳細はわかりませんが、現在の Python 2.7、Python 3 ではこれは "RuntimeError: maximum recursion depth exceeded in comparison" になります ---)。python-dev メーリングリストのアーカイブの 2000 年 4 月のスレッド "trashcan and PR#7" に、この実装に導いた議論といくつかの関連する有用なリンクがあります。また、比較は今では例外を投げることも出来ます。以前のバージョンの Python では `cmp(a,b)` のような比較操作は、ユーザ定義の `__cmp__()` メソッドがエラーを起こそうがそれ黙殺された上で、必ず何かの答えを出していました。

Work has been done on porting Python to 64-bit Windows on the Itanium processor, mostly by Trent Mick of ActiveState. (Confusingly, `sys.platform` is still `'win32'` on Win64 because it seems that for ease of porting, MS Visual C++ treats code as 32 bit on Itanium.) PythonWin also supports Windows CE; see the Python CE page at http://pythonce.sourceforge.net/ for more information.

Another new platform is Darwin/MacOS X; initial support for it is in Python 2.0. Dynamic loading works, if you specify "configure --with-dyld --with-suffix=.x". Consult the README in the Python source distribution for more instructions.

変数に値が割り当てられる前にローカル変数を参照するコードにおいて、 `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()` が、最初の引数が文字列である場合に「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` を定義することで、古い振る舞いに戻せます。これはお奨め出来ません。(---訳注: いつ消えたのかはわかりませんが 2.7 ではもちろん `NO_STRICT_LIST_APPEND` の ifdef は入っていません。---)

`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` を生成するでしょう。 (---訳注: 長整数の扱いはこのあとも Python 3 までの間に PEP 237 「長整数と整数の一体化」などを経て少しずつ区別がなくされていきました。 ---)

一番微妙な長整数についての変更は、長整数を `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'` となります。(---訳注: 精度がこれら2つで違うことについては今でも同じですが 2.7 に至るまでに浮動小数点数の扱い含め色々変更されているため、2.7 時点での `repr(8.1)` は `'8.1'` になります。まず現在の Python は単純に `sprintf()` を使っているのではなくもう少しだけ複雑なことをします。見かけ上は `%.16g` を使っているようにみえると思います。完全な詳細は `Objects/floatobject.c` を参照して下さい。---)

コマンドラインオプション `-X` を使って標準例外をクラスではなく文字列にする機能は削除されました。標準例外は今では常にクラスです。標準例外を含んでいる `exceptions` モジュールは Python からビルトインの C モジュールに変換されました。これは Barry Warsaw と Fredrik Lundh によって書かれました。

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

いくつかの変更点については覆いが被されていて、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 が変わるならプラットフォームに関係なくリコンパイルは常に必要です。 ---)

Users of Jim Fulton's ExtensionClass module will be pleased to find out that hooks have been added so that ExtensionClasses are now supported by `isinstance()` and `issubclass()`. This means you no longer have to remember to write code such as `if type(obj) == myExtensionClass`, but can use the more natural `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()`, and `PyModule_AddStringConstant()` です。これら関数のそれぞれは、モジュールオブジェクトと、追加されるべき名前を含む null 終端の C 文字列と、その名前に代入される値の、3 つの引数を取ります。3 つ目の引数は Python オブジェクトか、C の long か、C 文字列です。

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

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

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

配布のためのユーティリティについての SIG (---訳注: Python Special Interest Groups ---) が Greg Ward に主導されて、パッケージのインストールを格段に簡単にする Distutils を作りました。これにより `distutils` パッケージが、Python 標準ライブラリの新しい一部として形成されました。最良の場合にはソースから 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 の手による単純な XML パーサが、 `xmllib` モジュールの形で追加されました。1.5.2 でのリリース以降で、2 つの異なった XML 処理のインターフェイスが一般的になりました。SAX2 (「Simple API for XML」のバージョン 2) はいくらか `xmllib` に似た、イベントドリブンのインターフェイスを提供し、DOM (「Document Object Model］) は XML ドキュメントを、横断したり修正できるノードのツリーに変換する、木構造ベースのインターフェイスを提供します。Python 2.0 では SAX2 インターフェイスと必要最小限の DOM インターフェイスが、 `xml` パッケージの一部として追加されました。ここではそれら新規インターフェイスについての簡単な概要について書きます。完全な詳細については Python ドキュメントかソースコードを参照してください。Python XML SIG ではドキュメントの改善についても作業中です。

### SAX2 サポート

SAX は、XML のパースのイベントドリブンなインターフェイスを定義しています。SAX を利用するには、SAX ハンドラクラスを書く必要があります。ハンドラクラスは SAX により提供される様々なクラスから派生し、XML パーサから呼び出される様々なメソッドをオーバライドします。例えば、メソッド `startElement()` と `endElement()` はパーサによって開始・終了タグが検出されるたびに呼び出され、 `characters()` メソッドは文字データの塊 (chunk) ごとに呼び出される、といった具合です。

イベントドリブンのアプローチはドキュメント全体をいっときにメモリに持たなくて良い点で有利であり、ドキュメントが本当に巨大であるものを処理する際にはこれは重要です。ですが 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

    # Create a parser object
    parser = sax.make_parser()

    # Tell it what handler to use
    handler = SimpleHandler()
    parser.setContentHandler( handler )

    # Parse a file!
    parser.parse( 'hamlet.xml' )

もっと詳しい情報については Python ドキュメントを調べるか、 http://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 名前空間サポートを持つレベル 1 DOM の軽量実装です。コンビニエンス関数 `parse()` と `parseString()` が DOM ツリーの生成のために提供されています:

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

`doc` が `Document` のインスタンスです。DOM の全てのクラス、例えば `Element` や `Text` などや、 `Document` も、基底クラス `Node` のサブクラスです。ですので DOM ツリー内の全てのノードはある共通のメソッドを持ちます。例えば `toxml()` はそのノードとその子の XML 表現を含む文字列を返します。それぞれのクラスにはそれ自身の特別なメソッドも持ちます。例えば `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 の Web ページ 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 の追加機能には次のようなものがあります。

- 4DOM, a full DOM implementation from FourThought, Inc.

- The xmlproc validating parser, written by Lars Marius Garshol.

- The `sgmlop` parser accelerator module, written by Fredrik Lundh.

## 更新されたモジュール

Python 標準ライブラリに、広範囲に渡ってたくさんの改善とバグフィクスが行われました。この影響を受けたモジュールとしては `readline`, `ConfigParser`, `cgi`, `calendar`, `posix`, `readline`, `xmllib`, `aifc`, `chunk, wave`, `random`, `shelve`, `nntplib` があります。パッチごとにどのような改造が行われたのかの詳細は CVS ログを調べてください。

Brian Gallew が `socket` モジュールについての OpenSSL サポートを寄稿しました。OpenSSL はセキュアソケットレイヤーの実装の一つで、ソケットを通じて送信されるデータの暗号化を行います。Python コンパイル時に `Modules/Setup` を SSL サポートを含むように編集することで `socket` モジュールに追加機能を有効に出来ます: `socket.ssl(socket, keyfile, certfile)` はソケットオブジェクトを取り、SSL ソケットを返します。モジュール `httplib` と `urllib` も `https://` をサポートするように変更されましたが、SSL 経由の FTP と SMTP は実装されていません。 (---訳注: Python 2.1 (PEP 229) 以降から `Modules/Setup` を編集する必要はなくなっています。ソケットを SSL でラップするインターフェイスは今では(特に 2.7 のメンテナンスリリースで)もっと進化しています。ドキュメントを参照して下さい。SMTP over SSL は Python 2.2 でサポートされました。FTP については Python 2.7 で FTP_TLS がサポートされました。 ---)

`httplib` モジュールが、HTTP/1.1 をサポートするように Greg Stein により書き直されました。1.5 バージョンでの `httplib` との後方互換性は提供されていますが、パイプライン化のような 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` に取って代わるモジュールです。このためそれらは非推奨となりました。(Contributed by Gordon MacMillan and 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` モジュールの双子です。 (Contributed by Peter Bosch, with fixes by Jeremy Hylton.)

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

- `pyexpat`: Expat XML パーサへのインターフェイスです。 (Contributed by Paul Prescod.)

- `robotparser`: ウェブサイトの特定の領域を礼儀正しく避けるウェブスパイダを書くのに使われる `robots.txt` を解析します。パーサは `robots.txt` ファイルの中身を受け取ってそこからルールのセットを構築して、その上で指定した URL がフェッチ可能であるかどうかについての質問の答えを返します。(Contributed by 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` にこれを単に追加出来ますが、それらモジュールを使っているあらゆるコードは更新した方が良いです。(---訳注: `lib-old` は Python 2.5 で完全に削除されました。---)

## 謝辞

著者は提案の申し出や修正、様々なこの記事の草稿の助けをしてくれた以下の人々に感謝します: 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.