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 との関係
--------------

The XML Special Interest Group has been working on XML-related Python
code for a while.  Its code distribution, called PyXML, is available
from the SIG's Web pages at
https://www.python.org/community/sigs/current/xml-sig. The PyXML
distribution also used the package name "xml".  If you've written
programs that used PyXML, you're probably wondering about its
compatibility with the 2.0 "xml" package.

The answer is that Python 2.0's "xml" package isn't compatible with
PyXML, but can be made compatible by installing a recent version
PyXML.  Many applications can get by with the XML support that is
included with Python 2.0, but more complicated applications will
require that the full PyXML package will be installed.  When
installed, PyXML versions 0.6.0 or greater will replace the "xml"
package shipped with Python, and will be a strict superset of the
standard package, adding a bunch of additional features.  Some of the
additional features in PyXML include:

* 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" モジュールと較べて簡単な方法でカス
  タ ムなインポートフックを書くことが出来るモジュールです。
  (Implemented by Greg Stein, with much discussion on python-dev along
  the way.)


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.
