What's New in Python 2.3¶
- 著者:
A.M. Kuchling
この文書は Python 2.3 の新機能について解説します。Python 2.3 は 2003 年 7 月 29 日にリリースされました。
Python 2.3 の主要なテーマは、2.2 で追加されたいくつかの機能を磨くこと、言語中核に小さいながらも有用な種々の拡張をすること、そして標準ライブラリの拡充です。ひとつ前のバージョンで導入された新しいオブジェクトモデルは、18 ヶ月に渡るバグフィックスと新スタイルクラスの性能改善をもたらした最適化の努力の恩恵を受けました。 sum(), enumerate() のような、新たなビルトイン関数が少し追加されました。 in 演算子がサブストリングの検索に使えるようになりました (例えば "ab" in "abc" は True を返します)。
たくさんのライブラリ新機能…、Boolean、 set、 heap、 日付/時刻データ型、ZIP 形式アーカイブからのモジュールインポート、待ち望まれていた Python カタログのためのメタデータサポート、更新されたバージョンの IDLE、ロギングメッセージのためのモジュール、テキストの折り返し、CSV ファイルの解析、コマンドラインオプションの処理、BerkeleyDB データベースの使用…、新機能、強化機能のリストは長大になります。
このドキュメントは個々の新機能の完全な詳細を提供するのではなくて、簡易な概要を提供することを目的にしています。完全な詳細が知りたければ、 Python ライブラリリファレンス、Python リファレンスマニュアルのような Python 2.4 のドキュメントを参照してください。設計と実装の根拠を理解したい場合は、新機能に関する PEP を参照してください。
PEP 218: 標準の集合データ型¶
(---訳注: イキナリですが、あなたが今これを「Python の歴史を知る」もしくは「初登場時の熱量高い紹介」を読みたくて読んでいるのでない限りは、もしくは本当に今 2.3 を使う必要があれば別ですが、このモジュールは 2.4 で既にビルトインで置き換えられ、2.6 では非推奨となり、3.0 では削除されています。ので、集合型について知りたければここよりも 2.4 のビルトインの方から読んだ方が良いです。---) --- 新しいモジュール sets には、集合データ型の実装が含まれています。 Set クラスは mutable の集合のためのクラスで、メンバの追加と削除が出来ます。 ImmutableSet は変更できない集合のためのクラスなので、ImmutableSet のインスタンスを辞書のキーとして利用出来ます。集合型は辞書の上に構築されているので、集合内の要素はハッシュ可能でなければなりません。
単純な使用例です:
>>> import sets
>>> S = sets.Set([1,2,3])
>>> S
Set([1, 2, 3])
>>> 1 in S
True
>>> 0 in S
False
>>> S.add(5)
>>> S.remove(3)
>>> S
Set([1, 2, 5])
>>>
集合の和集合と共通部分は、union() メソッドと intersection() メソッドで計算できます。
ビット演算子 & と | を使う書き方もあります。
ミュータブルな集合には、これらの処理で集合自体を更新する union_update() メソッドと intersection_update() メソッドもあります。
>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([4,5,6])
>>> S1.union(S2)
Set([1, 2, 3, 4, 5, 6])
>>> S1 | S2 # 別の書き方
Set([1, 2, 3, 4, 5, 6])
>>> S1.intersection(S2)
Set([])
>>> S1 & S2 # 別の書き方
Set([])
>>> S1.union_update(S2)
>>> S1
Set([1, 2, 3, 4, 5, 6])
>>>
2 つの集合の対称差を取ることもできます。
これは、和集合に含まれる要素のうち共通部分に含まれない要素をすべて集めた集合です。
言い換えると、対称差は片方の集合だけに属するすべての要素を含みます。
こちらにも演算子 (^) を使う書き方と、symmetric_difference_update() という長い名前の、集合自体を更新するメソッドがあります。
>>> S1 = sets.Set([1,2,3,4])
>>> S2 = sets.Set([3,4,5,6])
>>> S1.symmetric_difference(S2)
Set([1, 2, 5, 6])
>>> S1 ^ S2
Set([1, 2, 5, 6])
>>>
issubset() と issuperset() メソッドも使えます。これはある集合が部分集合、上位集合であるかとうかをチェックします:
>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([2,3])
>>> S2.issubset(S1)
True
>>> S1.issubset(S2)
False
>>> S1.issuperset(S2)
True
>>>
参考
- PEP 218 - 集合オブジェクト型をビルトインに追加する
PEP 著 Greg V. Wilson. 実装: Greg V. Wilson, Alex Martelli, GvR. (---訳注: PEPそのものは 2.4 のビルトイン型 set, frozenset の追加と同じものですが、2.3 ではモジュールとして追加され、2.4 でビルトイン版が追加され、2.6 でモジュール版が非推奨となった、という流れです。---)
PEP 255: 単純なジェネレータ¶
Python 2.2 では、ジェネレータが from __future__ import generators ディレクティブで有効に出来るオプションの機能として追加されました。2.3 ではジェネレータは特別に有効化する必要なく、もうキーワード yield として、いつでもそこにあります。このセクションの残りの部分は "What's New in Python 2.2" のジェネレータの記述からの丸々コピーですので、2.2 のときに読んだなら読み飛ばしてもらって結構です。
Python や C の標準的な関数コールについては、よくご存じに違いありません。関数を呼ぶと、ローカル変数を作るプライベートな名前空間ができますね。その関数が return 文まで来ると、ローカル変数が破壊されてから、返り値が呼び出し元に返ります。次に同じ関数をもう一度呼ぶと、新しいプライベート名前空間に新規のローカル変数が作られるのです。しかし、関数を出るときにローカル変数を捨てなければどうなるでしょうか。その出ていったところから関数を続行できたとしたら、どうでしょう。これこそジェネレータが提供する機能です; すなわち、ジェネレータは続行できる関数と考えることができます。
ジェネレータ関数の最も単純な例です:
def generate_ints(N):
for i in range(N):
yield i
新しいキーワード yield がジェネレータのために導入されました。 yield ステートメントを含むどんな関数もジェネレータ関数です; Python バイトコードコンパイラはこれを検知し、関数が特別に扱われるように翻訳します。 (---訳注: Python 2.5 の PEP 342 も参照して下さい。この 2.2 で導入時点の yield はステートメントではなく式に変更されています。---)
ジェネレータ関数を呼び出すと、単一の値の代わりにイテレータプロトコルに対応したオブジェクトを返します。上の例で yield を実行したとき、ジェネレータは return 文のようにして i の値を生成します。 yield と return 文の大きな違いは、 yield に到達した段階でジェネレータの実行状態が一時停止になって、ローカル変数が保存される点です。次回そのジェネレータの .next() メソッドを呼ぶと、 yield の直後から関数が実行を再開します。(複雑な理由により、 yield は try...finally の try ブロック内に含めることは許されていません; PEP 255 に yield と例外の相互作用についての詳細説明がありますので参照して下さい。) --- (---訳注: Python 2.5 の PEP 342 で try...finally 内に置けないという制約はなくなりました。また、 try...finally の try 、とここであえて特定しているのは、同じく 2.5 の PEP 341 によって try/except/finally の一体化されるまでは、 finally の try と except の try が別物だったからです。---)
上記の generate_ints() ジェネレータはこんな具合に使います:
>>> gen = generate_ints(3)
>>> gen
<generator object at 0x8117f90>
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
2
>>> gen.next()
Traceback (most recent call last):
File "stdin", line 1, in ?
File "stdin", line 2, in generate_ints
StopIteration
同じく for i in generate_ints(5) や a,b,c = generate_ints(3) といった書き方もできます。
ジェネレータ関数内で return 文は、引数を付けずに、処理の終わりを知らせるためにだけ使うことができます; return を実行したあとは、もうそのジェネレータが値を返すことはできません。ジェネレータ関数の中では、 return 5 などと値を付けた return は構文エラーです。ジェネレータの出力が終わったことを示すには、ほかにも、手動で StopIteration を投げてもいいですし、関数の最後まで実行するだけでも同じことになります。(---訳注: Python 2.7 まではジェネレータ内での戻り値のある return 5 は構文エラーになりますが、少なくとも Python 3.4 で構文エラーとはなりません。単に無視されます。リファレンスに言及されていない振舞いなので、何かの事故かもしれません。いずれにせよジェネレータ内では Python 3 でも return で値は戻せません。---)
自分でクラスを書いて、ジェネレータで言うところのローカル変数をインスタンス変数として全部保管しておけば、同じ効果を得ることは可能です。たとえば整数のリストを返すのは、 self.count を 0 にして、 next() メソッドが self.count をインクリメントして返すようにすればできます。しかしながら、ある程度複雑なジェネレータになってくると、同じことをするクラスを書くのは格段にややこしいことになります。 Lib/test/test_generators.py にはもっと面白い例がたくさん含まれています。一番単純な一つは、ジェネレータを再帰的に使ってツリーを順繰りに横断する実装をするこれです (---訳注: ジェネレータは現在の最新 3.5 までの間に 2 度大きな機能強化が行われているのですが、一つが 2.5 での PEP 342 でこれは yield 「に」値を戻せるようにするものです。もう一つが 3.3 での PEP 380 で、これはサブジェネレータへの委譲 yield from <subgen> の追加でした。ですのでこの 3.3 からの yield from を使うと下記例はもっとスッキリ書けます。---):
# A recursive generator that generates Tree leaves in in-order.
def inorder(t):
if t:
for x in inorder(t.left):
yield x
yield t.label
for x in inorder(t.right):
yield x
ほかにも Lib/test/test_generators.py には、N-Queens 問題 (N×N コマのチェス盤に、互いに攻撃できないような配置で N 個のクイーンを置く) やナイト・ツアー (N×N 盤の全コマをナイトが一度ずつ通るような経路を探す) の解を出す例が入っています。
ジェネレータの発想はほかのプログラミング言語、特に Icon (https://www2.cs.arizona.edu/icon/) から着想しています。Icon ではジェネレータが言語の中枢になっています。Icon では、あらゆる式と関数がジェネレータのように振舞います。 https://www2.cs.arizona.edu/icon/docs/ipd266.htm の "Icon プログラミング言語の概要" の一つの例が、これがどのようなものであるのかを教えてくれます:
sentence := "Store it in the neighboring harbor"
if (i := find("or", sentence)) > 5 then write(i)
Icon では find() 関数は部分文字列 "or" が見つかる位置 3, 23, 33 を返します。 if 文内では i には最初 3 が代入されますが、これは 3 より小さいので比較は失敗し、Icon は次の値 23 を取り出します。 23 は 5 より大きいので比較は成功し、コードは 23 をスクリーンに表示します。
Python では Icon がそうするほどにはジェネレータを中心的概念に置きません。ジェネレータは Python 言語中核の新たな一面ではありますが、それらを学ぶのも使うのも誰しも行うべきだというものでもなく、そしてこれで解決できない何か問題があれば、忘れてしまっても良いものです。Icon と比較した特筆すべき Python インターフェイスの機能はジェネレータの状態が具象オブジェクト (イテレータ) で表現されることであり、それは他の関数に渡せますし、データ構造に記憶しておくことも出来ます。(---訳注: ジェネレータについてかなり控えめなのは、この時点で著者は将来の拡張を既に見据えていたから? かもしれませんね。PEP 342 と PEP 380 により今やジェネレータはこの頃より遥かに高機能になっており、今ではきっと「こんなものなくても困らない」なんて Python 使いはいないでしょう。---)
参考
- PEP 255 - 単純なジェネレータ
Neil Schemenauer, Tim Peters, Magnus Lie Hetland により著されました。実装のほとんどは Neil Schemenauer と Tim Peters により行われ、 Python Labs クルーにより他の修正が行われました。
PEP 263: ソースコードのエンコーディング¶
Python ソースファイルで、異なる文字セットエンコーディングを宣言出来るようになりました。エンコーディングはソースコードの 1 行目か 2 行目に特殊形式のコメントを含めることで宣言出来ます。 UTF-8 ファイルであればこのように宣言出来ます:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
このエンコーディング宣言がなければ、デフォルトの 7 ビット ASCII エンコーディングが使われます(訳注: Python 3 からはデフォルトは utf-8 (PEP 3120))。8 ビット文字を含んでいるのにエンコーディング宣言がないモジュールの実行やインポートを行うと、 Python 2.3 では DeprecationWarning を引き起こします; 2.4 ではこれは構文エラーになる予定です(訳注: 実際には 2.4 ではこれは実現せず、2.5 から)。
エンコーディング宣言は Unicode 文字列リテラルにのみ影響します。それらは指定したエンコーディングで Unicode 文字列に変換されます。Python 識別子は今でも ASCII 文字列に制限されていることに注意してください。ですから普通の英数字範囲外の文字を変数名に使うことは出来ません。
参考
- PEP 263 - Python ソースコードのエンコーディングを定義する
Marc-André Lemburg、 Martin von Löwis 著; Suzuki Hisao、 Martin von Löwis 実装.
PEP 273: Zip アーカイブからモジュールをインポートする¶
新たなモジュール zipimport が、ZIP フォーマットの書庫からモジュールのインポートをサポートします。 zipimport を明示的にインポートする必要はありません; sys.path に ZIP 形式書庫が追加されるとそれは自動的にインポートされます。例えば:
amk@nyman:~/src/python$ unzip -l /tmp/example.zip
Archive: /tmp/example.zip
Length Date Time Name
-------- ---- ---- ----
8467 11-26-02 22:30 jwzthreading.py
-------- -------
8467 1 file
amk@nyman:~/src/python$ ./python
Python 2.3 (#1, Aug 1 2003, 19:54:32)
>>> import sys
>>> sys.path.insert(0, '/tmp/example.zip') # パスの先頭に .zip ファイルを追加
>>> import jwzthreading
>>> jwzthreading.__file__
'/tmp/example.zip/jwzthreading.py'
>>>
sys.path には今や ZIP 書庫のファイル名も入れることが出来ます。ZIP アーカイブ内にはどんなファイルを置いてもかまいませんが、import できるのは *.py, *.pyc, *.pyo だけです。書庫に *.py だけが含まれる場合には、Python は書庫を修正して対応する *.pyc を作るなどということはしないので、 *.pyc ファイルを含まない ZIP 書庫からのインポートはやや遅いかもしれません。
書庫内のパスをサブディレクトリ以下のみインポートするように指定出来ます; 例えば、パス /tmp/example.zip/lib/ はその書庫内の lib/ サブディレクトリだけからインポートします。
参考
- PEP 273 - Zip アーカイブからモジュールをインポートする
このモジュールの実装も行った、James C. Ahlstrom による PEP です。 Python 2.3 は PEP 273 の仕様に従っていますが、 Just van Rossum の書いた、 PEP 302 に記述されているインポートフックによる実装を使っています。その新しいインポートフックについては PEP 302: 新たなインポートフック をみてください。
PEP 277: Windows NT での Unicode ファイル名サポート¶
Windows NT, 2000, XP では、ファイルシステムはファイル名として Unicode 文字列を使います。伝統的に Python はファイル名をバイト文字列として表現してきましたが、それはアクセス出来ないファイル名を表してしまう場合があって、不十分でした。
Python はいまや (ファイルシステムの制約の範囲内での) 任意の Unicode 文字列を open() 組み込み関数をはじめとするファイル名が期待される全ての関数で許容します。 os.listdir() に Unicode 文字列が渡されれば、Python は今では Unicode 文字列のリストを返します。新しい関数 os.getcwdu() は Unicode 文字列でカレントディレクトリを返します(訳注: ちなみに Python 3 での Unicode 周りの大改造に伴いこの関数はなくなり、代わりに「あえてバイト列のほうを返す」 os.getcwdb() が追加されています(os.getcwd() が Unicode を返すので)。)。
ファイル名のバイト文字列はいまでも動きます。Windows 版 Python は透過的にそれらを Unicode に mbcs エンコーディングを使って変換します。
ほかのシステムもファイル名に Unicode 文字列を使えますが、システムへ渡す前にバイト列に変換するため、UnicodeError が送出される場合があります。
アプリケーションは真偽値 os.path.supports_unicode_filenames を調べることで、任意の Unicode 文字列をファイル名に使えるかどうかを確認できます。
MacOS では、 os.listdir() は Unicode ファイル名を返すようになっているでしょう。
参考
- PEP 277 - Windows NT での Unicode ファイル名サポート
Neil Hodgson 著; 実装 Neil Hodgson, Martin von Löwis, Mark Hammond。
PEP 278: Universal Newline サポート¶
今日では 3 つの主要なオペレーティングシステムが使われています。 Microsoft Windows, Apple の Macintosh OS, さまざまな Unix 派生系です。テキストファイルの行終端マークに使う文字がこれら 3 つ全てでそれぞれ違っていることが、クロスプラットフォームのための仕事における小さな苛立ちです。 Unix が使うのはラインフィード (ASCII 文字 10), MacOS が使うのはキャリッジリターン (ASCII 文字 13), Windows に至ってはキャリッジリターンとラインフィード 2 文字のシーケンスを使います。
Python のファイルオブジェクトが、動作しているプラットフォームに従わない行終端変換をサポートするようになりました。ファイルのオープンにモード 'U' や 'rU' を使うと、 universal newlines モードを使った読み込みとしてファイルを開きます。これで read(), readline() などのファイルメソッドが、 3 つどの行終端でも '\n' という文字列に翻訳して返すようになります。
universal newline サポートはモジュールのインポートと execfile() 関数でのファイル実行にも使われます。これで 3 つ全てのオペレーティングシステム間で行終端変換の必要なく Python モジュールを共有出来ます。
この機能は Python をソースからビルドする際に configure スクリプトに --without-universal-newlines スイッチ を付けることで無効に出来ます。
参考
- PEP 278 : Universal Newline サポート
Jack Jansen 著、実装
PEP 279: enumerate()¶
新たな組み込み関数 enumerate() はある種のループ処理を少し簡潔にするものです。 thing がイテレータかシーケンスだとして、 enumerate(thing) は (0, thing[0]), (1, thing[1]), (2, thing[2]), … を生成するイテレータを返します。
リストの全てを変更するためのよくあるイディオムはこのようなものでしょう:
for i in range(len(L)):
item = L[i]
# ... item をもとに結果を計算 ...
L[i] = result
これは enumerate() を使ってこのように書き換えることが出来ます:
for i, item in enumerate(L):
# ... item をもとに結果を計算 ...
L[i] = result
参考
- PEP 279 - 組み込み関数 enumerate()
Raymond D. Hettinger 著、実装.
PEP 282: ロギングパッケージ¶
ログ記録のための標準パッケージ logging が Python 2.3 に追加されています。それはログ出力生成の強力で柔軟なメカニズムを提供し、フィルタと加工を色々な方法で行えます。標準フォーマットで書く設定ファイルで、プログラムのロギングの振る舞いを制御出来ます。ログレコードを標準エラー出力やファイルやソケット、システムログへの送信、あるいは e-mail 送信するようなハンドラが Python に含まれています。もちろん、あなた自身のハンドラクラスを書くことも出来ます。
Logger が最も重要なクラスです。ほとんどのアプリケーションコードは一つかそれ以上の Logger オブジェクトを扱い、それぞれ一つはそのアプリケーションの特定のサブシステムで使われるでしょう。それぞれの Logger は名前で識別され、名前は . をコンポーネントのセパレータとして使う階層で体系化されます。例えば、 server, server.auth, server.network といった名前の Logger インスタンスを持つといった具合です。この例の後ろ 2 つは階層で server の下にあります。 server への冗長性を見つけた場合や server メッセージを直接異なるハンドラに向けた場合、変更は server.auth と server.network へのログ記録にも適用されるということです。全てのほかのロガーの親となる、ルート Logger もあります。
単純な用法のために、 logging パッケージはいくつかの便利関数を含んでいて、これは常にルートログを使います:
import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')
これは以下のような出力をします:
WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down
デフォルトの設定では、情報やデバッグ用のメッセージは出力されず、出力先は標準エラーです。
ルートロガーの setLevel() メソッドを呼び出すと、情報やデバッグ用のメッセージも表示するようにできます。
warning() の呼び出しで文字列の書式化演算子を使っている点に注目してください。
メッセージを記録する関数はすべて (msg, arg1, arg2, ...) という引数を取り、msg % (arg1, arg2, ...) の結果の文字列を記録します。
直近のトレースバックを記録する exception() 関数もあります。
ほかの関数でも、キーワード引数 exc_info に真の値を指定すればトレースバックを記録します。
def f():
try: 1/0
except: logging.exception('Problem recorded')
f()
これは以下のような出力をします:
ERROR:root:Problem recorded
Traceback (most recent call last):
File "t.py", line 6, in f
1/0
ZeroDivisionError: integer division or modulo by zero
多少なりとも高度なプログラムでは、ルートロガー以上のロガーを使うでしょう。 getLogger(name) 関数は特定のロガーを取得するのに使います。その時点で存在していなければ、作成されます。 getLogger(None) はルートロガーを返します。:
log = logging.getLogger('server')
...
log.info('Listening on port %i', port)
...
log.critical('Disk full')
...
ログレコードは通常、階層を上に向かって伝わるので、server.auth に記録したメッセージは server や root でも確認できます。
ただし Logger の propagate 属性を False にすると、この伝播を止められます。
logging パッケージには、カスタマイズ可能なクラスがほかにもあります。
Logger インスタンスにメッセージの記録を指示すると、LogRecord インスタンスが作られ、任意の数の Handler インスタンスに送られます。
ロガーとハンドラーにはフィルターのリストを取り付けることもでき、各フィルターは LogRecord を無視したり、次へ渡す前に変更したりできます。
最終的な出力の際には、Formatter クラスによって LogRecord インスタンスがテキストに変換されます。
これらのクラスはすべて、自分で書いた専用のクラスに置き換えられます。
これら全ての機能で logging パッケージは最も複雑なアプリケーションでさえ、十分な柔軟性を提供しているはずです。ここではそれら機能の不完全な概要しか示しませんでしたので、全ての詳細はパッケージのドキュメントを参照してください。 PEP 282 を読むことも助けになるでしょう。(---訳注: 今ではクックブックもあるのでそちらもどうぞ。---)
参考
- PEP 282 - ログシステム
PEP 著: Vinay Sajip と Trent Mick; 実装: Vinay Sajip.
PEP 285: Boolean 型¶
Python 2.3 に真偽値型が加わりました。
__builtin__ モジュールに 2 つの新しい定数 True と False が追加されました。
(True と False という定数自体は Python 2.2.1 で組み込みに追加されていましたが、2.2.1 では単に整数値 1 と 0 を設定したもので、別の型ではありません。)
この新しい型の型オブジェクトの名前は bool です; これのコンストラクタは任意の Python 値を取り、 True または False に変換します:
>>> bool(1)
True
>>> bool(0)
False
>>> bool([])
False
>>> bool( (1,) )
True
標準ライブラリモジュールとビルトイン関数のほとんどが、そうすべきときには Boolean を返すように変更されました:
>>> obj = []
>>> hasattr(obj, 'append')
True
>>> isinstance(obj, list)
True
>>> isinstance(obj, tuple)
False
Python の Boolean はコードを明快にすることを主たる目標として追加されました。例えばあなたがコードを読んでいて return 1 に出くわした場合、あなたは考えるはずです。この 1 は、真偽としての真値なのであろうか、それともインデクスだろうか、はたまた何かほかの数量に掛ける係数だろうか、と。 return True であればその意味するところはかなり明らかです。
Python の Boolean は、厳格な型チェックを目的として追加された のではありません 。Pascal のようなとても厳格な言語では、Boolean の数学演算も阻むでしょうし、 if ステートメントの式が必ず Boolean の結果に評価されなければならないことを要求するでしょう。 Python はこの厳しさを今持ちませんし、 PEP 285 が名言するように、未来永劫持つことはありません。このことは、 if ステートメントにこれからも任意の式を書けることを意味しますし、リストやらタプルやら何かほかのデタラメなオブジェクトに評価されるものでも良いことを意味します。Boolean 型は int クラスのサブクラスであって、Boolean の算術演算はこれからも動作します:
>>> True + 1
2
>>> False + 1
1
>>> False * 75
0
>>> True * 75
75
True と False はぶっちゃけて言えば…: これらは整数値 1 と 0 の別名だけれども唯一異なるのは str() と repr() が '1' と '0' ではなく 'True' と 'False' を返すことだけである。
参考
- PEP 285 - 真偽値型の追加
Guido van Rossum 著、実装
PEP 293: コーデックエラーを処理するコールバック¶
Unicode 文字列をバイト文字列にエンコードする際には、エンコード出来ない文字に出会うことがあります。いまのところ Python は、そのエラー処理として "strict" (UnicodeError を発生させる)、 "ignore" (その文字をスキップする)、 "replace" (出力文字列ではクエッションマークに置換する)、のいずれか一つを指定出来て、 "strict" がデフォルトの振る舞いになっています。その種のエラーのために、ほかの代わりとなる処理が望ましいかもしれません。例えば XML や HTML の実体参照に置き換えるなどの。
Python は今や、異なる処理戦略を追加する柔軟なフレームワークを手にしました。新しいエラーハンドラを codecs.register_error() で追加出来、コーデックは codecs.lookup_error() を使ってそのエラーハンドラにアクセス出来ます。等価な C API も C で書かれたコーデックのために追加されています。エラーハンドラは、変換すべき文字列、そのエラーが検出されたその文字列内での位置、ターゲットエンコーディングのような必要な状態情報を受け取ります。ハンドラは例外を投げるか、置換文字列を返せます。
このフレームワークを使って 2 つのエラーハンドラが実装されました: "backslashreplace" はエンコード出来ない文字をバックスラッシュで引用し、 "xmlcharrefreplace" は XML 文字参照を発行します。
参考
- PEP 293 - コーデックエラーを処理するコールバック
Walter Dörwald 著、実装
PEP 301: パッケージインデクスと、 Distutils のためのメタデータ¶
長い間要望されてきた Python カタログのサポートが 2.3 で初登場です。
カタログの心臓部は Distutils の新コマンド register です。 python setup.py register を実行すると、名前、バージョン、メンテナ、説明、ライセンスのようなパッケージ記述のメタデータを収集して、中央カタログサーバに送信します。結果のカタログは https://pypi.org で利用可能です。
カタログをより便利にするため、Distutils の setup() 関数に新しい省略可能なキーワード引数 classifiers が追加されました。
ソフトウェアの分類に役立つ Trove 形式の文字列のリストを指定できます。
以下は setup.py に分類指定子 (classifier) を記述する例です。 Distutils の古いバージョンと互換になるように書いています。:
from distutils import core
kw = {'name': "Quixote",
'version': "0.5.1",
'description': "A highly Pythonic Web application framework",
# ...
}
if (hasattr(core, 'setup_keywords') and
'classifiers' in core.setup_keywords):
kw['classifiers'] = \
['Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Environment :: No Input/Output (Daemon)',
'Intended Audience :: Developers'],
core.setup(**kw)
classifier の完全なリストは python setup.py register --list-classifiers と実行することで得ることが出来ます。
参考
- PEP 301 - パッケージインデクスと、 Distutils のためのメタデータ
Richard Jones 著、実装
PEP 302: 新たなインポートフック¶
カスタムなインポートフックを書くことは、Python 1.3 で ihooks モジュールが導入されたその日からずっと可能でした。それでも本当のところそれで幸せになった人は誰一人いません。それで新しいインポートフックを書くのが難しくてとっ散らかっていたからです。 imputil と iu モジュール のような代わりとなる色々な提案がありましたが、そのいずれも多くの賛同を得ることが出来たものはありませんし、そのいずれもが簡単に C コードから使うことが出来ませんでした。
PEP 302 はその先駆者、特に Gordon McMillan の iu モジュールからアイディアを借りています。3 つの新たなアイテムが sys モジュールに追加されています:
sys.path_hooksは呼び出し可能オブジェクトのリストです。ほとんどの場合クラスになるでしょう。それぞれの呼び出し可能オブジェクトは、パスを含む文字列を受け取って、このパスからインポートを処理するインポーターオブジェクトを返すか、このパスを処理出来なければImportErrorを送出します。sys.path_importer_cacheはそれぞれのパスごとのインポーターオブジェクトをキャッシュしますので、sys.path_hooksは個々のパスを一回だけ横断すれば良いことになります。sys.meta_pathはsys.pathがチェックされる前に横断させるインポーターオブジェクトのリストです(訳注: ここだけ読むとわかりにくいですがライブラリリファレンスを読めばわかります)。このリストは初期状態で空ですが、ユーザコードがオブジェクトをそれに追加出来ます。追加のビルトインと凍結モジュールを、このリストにオブジェクトを追加することによってインポートさせることが出来ます。
インポーターオブジェクトは一つのメソッド find_module(fullname, path=None) を持たなければなりません。 fullname はモジュールかパッケージの名前です。例えば string や distutils.core です。 find_module() メソッドは一つのメソッド load_module(fullname) を持つローダーオブジェクトを返さなければなりません。 load_module(fullname) では対応するモジュールオブジェクトを生成して返します。
Python の新しいインポートのロジックは、なので、擬似コードで示すとだいたいこんな感じです (少し単純化しています; 完全な詳細は PEP 302 参照):
for mp in sys.meta_path:
loader = mp(fullname)
if loader is not None:
<module> = loader.load_module(fullname)
for path in sys.path:
for hook in sys.path_hooks:
try:
importer = hook(path)
except ImportError:
# ImportError なので、ほかのパスフックを試す
pass
else:
loader = importer.find_module(fullname)
<module> = loader.load_module(fullname)
# 見つからなかった!
raise ImportError
参考
- PEP 302 - 新たなインポートフック
Just van Rossum、Paul Moore 著、実装 Just van Rossum。
PEP 305: カンマ区切り形式ファイル¶
カンマ区切りファイルは、データベースやスプレッドシートからのエキスポートのために頻繁に使われるフォーマットです。Python 2.3 はカンマ区切りファイルのパーサを追加しました。
カンマ区切りフォーマットは、ぱっと見で、簡単そうに見えます:
Costs,150,200,3.95
行を読んで line.split(','): これほどに簡単なものはあるだろうか、って? ですが、文字列データ内にカンマを含んだりすると、コトは複雑になります:
"Costs",150,200,3.95,"Includes taxes, shipping, and sundry items"
デカくて醜い正規表現でこれをパース出来るでしょうが、新登場の csv を使えば遥かに単純になります:
import csv
input = open('datafile', 'rb')
reader = csv.reader(input)
for line in reader:
print line
reader() 関数にはさまざまなオプションがあります。
フィールドの区切りはカンマに限らず、任意の文字に変更でき、引用符や行末の文字も同様に変更できます。
カンマ区切りファイルの異なった方言を定義して登録出来ます。今のところ 2 つの方言があって、両者とも Microsoft Excel で使われるものです。独立している csv.writer はタプルやリストの連続から、デリミタを含む文字列は引用符で囲みつつカンマ区切りファイルを生成します。
参考
- PEP 305 - CSV File API
PEP 著と実装: Kevin Altis, Dave Cole, Andrew McNamara, Skip Montanaro, Cliff Wells.
PEP 307: Pickle の機能拡張¶
2.3 の開発では pickle モジュールと cPickle モジュールにも手が加えられました。
2.2 でも新スタイルクラスは問題なく pickle 化できましたが、その結果はあまりコンパクトではありませんでした。
PEP 307 には、新スタイルクラスの pickle 化で得られる文字列が旧スタイルクラスの場合の 3 倍の長さになる簡単な例が挙げられています。
解決方法として、新しい pickle プロトコルが発明されました。 pickle.dumps() 関数はずっと長い間、テキストとするのかバイナリとするのかについてはサポートしていました。2.3 ではこのフラグは Boolean から整数に再定義されました: 0 は旧式のテキストモード pickle フォーマット、1 が同じく旧式のバイナリフォーマット、そして 2 が今回の 2.3 から特有のフォーマットです。新しく追加された定数 pickle.HIGHEST_PROTOCOL を指定すると、最も望ましいものが選択されます。
pickle の復元は、もはや安全な操作とはみなされません。
2.2 の pickle には、安全でないクラスの復元を防ぐためのフック (具体的には __safe_for_unpickling__ 属性) がありましたが、そのコードは一度も監査されていなかったため、2.3 ですべて削除されました。
Python のどのバージョンでも、信頼できないデータから pickle を復元してはいけません。
新スタイルクラスの pickle 化のオーバーヘッドを減らすため、3 つの特殊メソッド __getstate__()、__setstate__()、__getnewargs__() で pickle 化をカスタマイズする新しいインターフェースが追加されました。
これらのメソッドの詳しい意味については PEP 307 を参照してください。
pickle をもっとさらに圧縮する方法として、pickle されるクラスの身元特定のために長い文字列を使う代わりに整数コードを使えるようになっています。Python Software Foundation は標準コードのリストを保守しています; プライベート使用のためのコード範囲もあります。現在のところ指定されているコードはありません。
参考
- PEP 307 - pickle プロトコルの拡張
著、実装: Guido van Rossum と Tim Peters
拡張スライス¶
Python 1.4 以来ずっと、スライシングの構文は省略可能な 3 つ目の引数 "step" またの名を "stride" 、をサポートしていたのです。例えばこれらは全て合法な Python 構文です: L[1:10:2], L[:-1:1], L[::-1] 。これはこの 3 つ目の引数を大々的に使う Numerical Python 開発者によって要望されたことで Python に追加されたものですが、Python ビルトインのリスト、タプル、文字列といったシーケンス型がこの機能をサポートすることはなく、これを試みると TypeError を起こしていました。Michael Hudson がこの不徹底を修正するパッチを寄稿しました。
例えば、今やリストの偶数番目要素を簡単に取り出せます:
>>> L = range(10)
>>> L[::2]
[0, 2, 4, 6, 8]
負の値では、同じリストの逆順コピーを作るように動作します:
>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
これはタプル、配列、文字列に対しても使えます:
>>> s='abcd'
>>> s[::2]
'ac'
>>> s[::-1]
'dcba'
リストや配列のような mutable なシーケンスに対して、拡張スライスを代入や削除に使えますが、拡張スライスと普通のスライスではいくつかの違いがあります。普通のスライスで代入を行えば、シーケンスの長さを変更出来ます (---訳注: 念のため。Python 3 の range は list を直接返す関数ではなくジェネレータなので、以下例は a = list(range(3)) などとしないと動作しません。続く例でも同じです。---):
>>> a = range(3)
>>> a
[0, 1, 2]
>>> a[1:3] = [4, 5, 6]
>>> a
[0, 4, 5, 6]
拡張スライスにはこの柔軟性はありません。拡張スライスを代入に使う際は、ステートメントの右辺のリストは、置換されるスライスとしての要素数と同数でなければなりません:
>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> a[::2] = [0, -1]
>>> a
[0, 1, -1, 3]
>>> a[::2] = [0,1,2]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: attempt to assign sequence of size 3 to extended slice of size 2
削除はもっと素直です:
>>> a = range(4)
>>> a
[0, 1, 2, 3]
>>> a[::2]
[0, 2]
>>> del a[::2]
>>> a
[1, 3]
組み込みシーケンスの __getitem__() メソッドにスライスオブジェクトを渡せるようにもなりました。
>>> range(10).__getitem__(slice(0, 5, 2))
[0, 2, 4]
あるいは直接 slice オブジェクトを添え字に使えます:
>>> range(10)[slice(0, 5, 2)]
[0, 2, 4]
拡張スライスに対応するシーケンスを簡単に実装できるよう、スライスオブジェクトに indices(length) メソッドが追加されました。
シーケンスの長さを渡すと、range() にそのまま渡せる (start, stop, step) タプルを返します。
indices() は、省略されたインデックスや範囲外のインデックスを通常のスライスと同じ規則で扱います (この何気ない表現の裏には、ややこしい詳細が山ほど隠れています!)。
このメソッドは次のように使うことを想定しています。
class FakeSeq:
...
def calc_item(self, i):
...
def __getitem__(self, item):
if isinstance(item, slice):
indices = item.indices(len(self))
return FakeSeq([self.calc_item(i) for i in range(*indices)])
else:
return self.calc_item(i)
ところでこの例からは、ビルトインの slice オブジェクトが今では slice 型という型オブジェクトで、もう関数ではないことがわかるでしょう。これは、Python 2.2 で int, str などに対して行われた同じ目的の修正と一貫しています。
その他の言語変更¶
以下が、Python 2.3 言語コアに加えられた全ての変更点です。
yield文がこのドキュメントの PEP 255: 単純なジェネレータ で述べた通り、キーワードになっています。新たな組み込み関数
enumerate()が追加されました。このドキュメントの PEP 279: enumerate() で述べた通りです。新たな定数
True,Falseがビルトインbool型の追加に伴い追加されました。このドキュメントの PEP 285: Boolean 型 で述べた通りです。int()型コンストラクタは、文字列や浮動小数点数を整数に収める際、それがとても大き場合にOverflowErrorを投げるのではなく長整数を返すようになっています。これはisinstance(int(expression), int)が偽を返すかもしれないという逆説的な結果をもたらし得ますが、これが実際に問題を起こすとはあまり思えません。ビルトイン型が拡張スライス構文をサポートするようになりました。このドキュメントの 拡張スライス で述べた通りです。
新規組み込み関数
sum(iterable, start=0)はイテラブル オブジェクト内の数値アイテムを足し込んで総和を返します。sum()は数値しか受け付けませんので、文字列群を連結するのには使えません。 (Contributed by Alex Martelli.)list.insert(pos, value)で value を先頭に追加するのに pos に負数が使われてきました。この振る舞いはスライスのインデクシングとの一貫性のために変更されました。つまり pos が -1 の場合は最終要素の前への追加、などとなります。list.index(value)はリスト内から value を探してそのインデクスを返しますが、オプショナルな start と stop 引数を取って、リストの部分列からの検索が可能になりました。辞書の新たなメソッド
pop(key[, *default*])は、 key に対応する値を返して辞書からそのキー/値ペアを取り除きます。辞書内にそのキーが不在であれば、 default が指定されていればそれを、そうでなければKeyErrorを投げます。:>>> d = {1:2} >>> d {1: 2} >>> d.pop(4) Traceback (most recent call last): File "stdin", line 1, in ? KeyError: 4 >>> d.pop(1) 2 >>> d.pop(1) Traceback (most recent call last): File "stdin", line 1, in ? KeyError: 'pop(): dictionary is empty' >>> d {} >>>
また、新しいメソッド
dict.fromkeys(iterable, value)は、与えられたイテレータ iterable からキーを取り出しつつ全ての値を value にセットすることで構築します。 value のデフォルトはNoneです。(Patches contributed by Raymond Hettinger.)
また、
dict()コンストラクタは小さな辞書を簡単に構築出来るよう、キーワード引数を受け付けるようになりました:>>> dict(red=1, blue=2, green=3, black=4) {'blue': 2, 'black': 4, 'green': 3, 'red': 1}
(Contributed by Just van Rossum.)
assertステートメントが__debug__フラグをチェックすることはもうありません。このため、__debug__に代入することによってアサーションを無効にすることは出来ません。Python を-Oスイッチで起動により全てのアサーションが実行されない点は、以前と変わりません。ほとんどの型オブジェクトが今では呼び出し可能であり、なので関数、クラス、モジュールのようなオブジェクトを新たに構築するのにそれを使えます。 (
newモジュールはこれにより将来のバージョンの Python で撤廃される可能性があります。typesモジュール内の型オブジェクトが使えるからです。 ---訳注: 2.6 で実際に撤廃されています。---) 例えば、新規モジュールオブジェクトは以下コードで構築出来ます:>>> import types >>> m = types.ModuleType('abc','docstring') >>> m <module 'abc' (built-in)> >>> m.__doc__ 'docstring'
新たな警告
PendingDeprecationWarningが、将来廃止される予定のある機能であることを示すために追加されました。この警告はデフォルトで 出力されません 。将来において廃止される予定の機能の使用をチェックするにはコマンドラインから-Walways::PendingDeprecationWarning::を与えるか、warnings.filterwarnings()を使います。文字列ベースの例外、例えば
raise "Error occurred"のようなもの、これは廃止のための過程を開始しています。文字列を例外として投げるとPendingDeprecationWarningが発行されます。Noneを変数名に使うとSyntaxWarning警告を出すようになっています。将来バージョンの Python ではNoneはキーワードになります。ファイルが自分自身のイテレータとして振る舞うようになったため、Python 2.1 で追加されたファイルオブジェクトの
xreadlines()メソッドは不要になりました。xreadlines()は、ファイルのすべての行を高速にループで処理するために導入されましたが、今では単にfor line in file_objと書けます。 また、ファイルオブジェクトには、使用するエンコーディングを示す読み出し専用のencoding属性が加わりました。 ファイルに書き込む Unicode 文字列は、指定されたエンコーディングで自動的にバイト列へ変換されます。新スタイルクラスのメソッド解決順序が変わりましたが、非常に複雑な継承階層でなければ違いに気づかないでしょう。 旧スタイルクラスはこの変更の影響を受けません。 Python 2.2 はもともとクラスの祖先をトポロジカルソートしていましたが、2.3 は論文 "A Monotonic Superclass Linearization for Dylan" で説明された C3 アルゴリズムを使います。 変更の動機については、Michele Simionato の記事 Python 2.3 のメソッド解決順序 または https://mail.python.org/pipermail/python-dev/2002-October/029035.html のメッセージで始まる python-dev のスレッドを読んでください。 Samuele Pedroni が最初に問題を指摘し、C3 アルゴリズムを実装して修正も行いました。
Python は N 個のバイトコードを実行するたびにスレッドを切り替えて、マルチスレッドのプログラムを実行します。 N のデフォルト値が 10 から 100 に増え、切り替えのオーバーヘッドが減ることでシングルスレッドのアプリケーションが高速になりました。 一部のマルチスレッドアプリケーションでは応答が遅くなる可能性がありますが、
sys.setcheckinterval(N)でこの値を小さく戻せば簡単に対処できます。 この値は新しいsys.getcheckinterval()関数で取得できます。マイナーですが広範囲に渡る変更として、拡張型の名前の変更があります。Python と一緒に含まれるモジュールで定義される拡張型の名前が、モジュール名と
'.'が型名に前置されるようになりました。例えば、Python 2.2 ではソケットオブジェクトを作って__class__を出力すると、このような出力だったでしょう:>>> s = socket.socket() >>> s.__class__ <type 'socket'>
2.3 ではこうなります:
>>> s.__class__ <type '_socket.socket'>
旧スタイルクラスと新スタイルクラスの既知の非互換性が一つ解消されました。 新スタイルクラスの
__name__属性と__bases__属性に代入できるようになりました。__bases__に代入できる値には、インスタンスの__class__属性への代入と同様の制約があります。
文字列に関する変更¶
in演算子が文字列に対して違った振る舞いをするようになりました。以前は X と Y が文字列の場合のX in Yは、 X は単一文字でなければなりませんでした。これが X はどんな長さでも良くなり、X in Yは X が Y のサブストリングであればTrueを返すように変更されました。 X が空文字列の場合は結果は常にTrueになります。>>> 'ab' in 'abcd' True >>> 'ad' in 'abcd' False >>> '' in 'abcd' True
これはサブストリングの開始位置を教えてくれるわけではないので、その情報が必要であれば
find()文字列メソッドを使ってください。strip(),lstrip(),rstrip()に、剥ぎ取る文字を指定する省略可能な引数が追加されています。デフォルトは従来通り全ての空白文字を削除します。:>>> ' abc '.strip() 'abc' >>> '><><abc<><><>'.strip('<>') 'abc' >>> '><><abc<><><>\n'.strip('<>') 'abc<><><>\n' >>> u'\u4000\u4001abc\u4000'.strip(u'\u4000') u'\u4001abc' >>>
(Suggested by Simon Brunning and implemented by Walter Dörwald.)
文字列の
startswith()メソッドとendswith()メソッドが、start パラメーターと end パラメーターの負の値を受け付けるようになりました。もう一つの新しい文字列メソッドは
zfill()で、もともとはstringモジュールの関数でした。zfill()は、数を表す文字列が指定した幅になるまで左側をゼロで埋めます。 ただし、%演算子の方がzfill()よりも柔軟で高機能です。>>> '45'.zfill(4) '0045' >>> '12345'.zfill(4) '12345' >>> 'goofy'.zfill(6) '0goofy'
(Contributed by Walter Dörwald.)
新しい型オブジェクト
basestringが加わりました。 8 ビット文字列と Unicode 文字列の両方がこの型を継承するので、isinstance(obj, basestring)はどちらの文字列に対してもTrueを返します。 これは完全に抽象的な型なので、basestringのインスタンスは作れません。内部化した文字列はもう不死身ではないので、内部辞書からの参照が、参照している唯一のものとなれば、普通にガーベージコレクト対象となります。 (Implemented by Oren Tirosh.)
最適化¶
新スタイルクラスのインスタンスの作成が大幅に高速化され、旧スタイルクラスより速くなりました!
Tim Peters がリストオブジェクトの
sort()メソッドを大幅に書き直し、実装がかなり高速になりました。Karatsuba 乗算が実装され、大きな長整数の乗算が大幅に高速になりました。 このアルゴリズムは、学校で習う筆算の乗算アルゴリズムに必要な O(n2) よりも、桁数が増えたときの計算量の増加を抑えられます。 (最初のパッチは Christopher A. Craig によるもので、Tim Peters が大幅に手を加えました。)
SET_LINENOオペコードが削除されました。 コンパイラーの特性によっては、これにより多少高速になる場合があります。 詳しい説明は その他の変更と修正 を参照してください。 (Michael Hudson が削除しました。)xrange()オブジェクトが専用のイテレータを持つようになり、for i in xrange(n)はfor i in range(n)よりわずかに高速になりました。 (Raymond Hettinger によるパッチです。)性能向上のため、頻繁に実行される箇所で関数のインライン化やコードの削除など、多数の小さな変更が行われました。 (主な実装者は GvR ですが、多くの人が個々の変更を提供しました。)
2.3 での最適化を総合すると、Python 2.3 は pystone ベンチマークを Python 2.2 より約 25% 高速に実行します。
新たなモジュール、改良されたモジュール、非推奨のモジュール¶
いつものように、Python の標準ライブラリには数多くの拡張とバグ修正がありました。ここでは最も注目に値する変更について、モジュールの辞書順に列挙します。変更の完全なリストについてはソースツリーの Misc/NEWS を調べるか、あるいは全ての詳細について CVS ログに目を通してみてください。
arrayモジュールが'u'フォーマット文字を使った Unicode 文字の配列をサポートするようになっています。配列はまた、+=代入演算子を使ってほかの配列内容を加算すること、*=演算子を使って配列を繰り返すことが可能になっています。(Contributed by Jason Orendorff.)bsddbモジュールが PyBSDDB バージョン 4.1.6 によって置き換えられています。これは BerkeleyDB のトランザクションの機能へのより完全なインターフェースを提供します。古いバージョンのモジュールは
bsddb185にリネームされて、自動的にはビルドされません。有効にするにはModules/Setupを編集する必要があります。新しいbsddbパッケージは古いモジュールと互換となるように意図されていますので、何か非互換を見つけたらファイルのバグを確認してください。Python 2.3 へのアップグレードの際、前提となる BerkeleyDB ライブラリの新バージョンでインタープリタがコンパイルされるならば、ほぼ確実にあなたのデータベースは新バージョンに変換しなければならないでしょう。ソース配布物のTools/scriptsディレクトリのdb2pickle.pyとpickle2db.pyスクリプトを使って、これをかなり簡単に行うことが出来ます。もし既に PyBSDDB パッケージを使っていてbsddb3としてインポートしているならば、bsddbをインポートするようにimport文を変更する必要があります。新規の
bz2モジュールは bz2 データ圧縮ライブラリへのインターフェイスです。bz2 圧縮データは普通zlib圧縮データよりも小さくなります。 (Contributed by Gustavo Niemeyer.)標準の日付時刻型が
datetimeモジュールとして追加されています。詳細はこのドキュメントの下の方に記述してありますのでそちらを参照して下さい。Distutils の
Extensionクラスに、拡張モジュールが依存する追加のソースファイルを列挙するコンストラクター引数 depends が加わりました。 これにより、依存先のファイルが変更されると Distutils がモジュールを再コンパイルします。 例えばsampmodule.cがヘッダーファイルsample.hをインクルードしている場合、Extensionオブジェクトは次のように作ります。ext = Extension("samp", sources=["sampmodule.c"], depends=["sample.h"])
sample.hを修正するとモジュールは再コンパイルされます。 (Contributed by Jeremy Hylton.)Distutils のその他の小さな変更として、環境変数
CC、CFLAGS、CPP、LDFLAGS、CPPFLAGSを確認し、Python の構成設定を上書きするようになりました (Robert Weber による貢献です)。これまで
doctestモジュールは公開メソッドや公開関数の docstring からだけテストケースを探していましたが、非公開のものも調べるようになりました。DocTestSuite()関数は、一連のdoctestテストからunittest.TestSuiteオブジェクトを作成します。新しい関数
gc.get_referents(object)は object により参照されている全てのオブジェクトのリストを返します。getoptモジュールに新しい関数gnu_getopt()が加わりました。 既存のgetopt()関数と同じ引数に対応しますが、GNU 形式の走査モードを使います。 従来のgetopt()はオプションでない引数に出会うとオプションの処理を終了しますが、GNU 形式では処理を続けるため、オプションと引数を混在させられます。 例えば次のようになります。>>> getopt.getopt(['-f', 'filename', 'output', '-v'], 'f:v') ([('-f', 'filename')], ['output', '-v']) >>> getopt.gnu_getopt(['-f', 'filename', 'output', '-v'], 'f:v') ([('-f', 'filename'), ('-v', '')], ['output'])
(Contributed by Peter Åstrand.)
モジュール
grp,pwd,resourceでは拡張されたタプルを返すようになりました:>>> import grp >>> g = grp.getgrnam('amk') >>> g.gr_name, g.gr_gid ('amk', 500)
gzipモジュールが 2 GiB を超えるファイルを扱えるようになっています。新しい
heapqモジュールには、ヒープキューアルゴリズムの実装が含まれています。 ヒープは配列のようなデータ構造で、すべてのインデックス k についてheap[k] <= heap[2*k+1]およびheap[k] <= heap[2*k+2]が成り立つよう、要素を部分的に整列して保持します。 これによって最小の要素を素早く取り除け、ヒープの性質を維持しながら新しい要素を挿入する計算量は O(log n) です。 (優先度キューというデータ構造の詳細は https://xlinux.nist.gov/dads//HTML/priorityque.html を参照してください。)heapqモジュールは、ほかのミュータブルな Python のシーケンス型を使い、ヒープの性質を保って要素を追加・削除するheappush()関数とheappop()関数を提供します。 Python のリストを使う例を示します。>>> import heapq >>> heap = [] >>> for item in [3, 7, 5, 11, 1]: ... heapq.heappush(heap, item) ... >>> heap [1, 3, 5, 11, 7] >>> heapq.heappop(heap) 1 >>> heapq.heappop(heap) 3 >>> heap [5, 7, 11]
(Contributed by Kevin O'Connor.)
統合開発環境 IDLE が、IDLEfork プロジェクト (https://idlefork.sourceforge.net) のコードを使って更新されました。 最も目立つ特徴は、開発中のコードがサブプロセスで実行されるようになったことです。 これにより、手動で
reload()を実行する必要がなくなりました。 IDLE の中核となるコードは、idlelibパッケージとして標準ライブラリに組み込まれました。imaplibモジュールが IMAP over SSL をサポートするようになりました. (Contributed by Piers Lauder and Tino Lange.)itertoolsには、ML や Haskell が提供するさまざまな関数に着想を得た、イテレータで使える便利な関数が含まれています。 例えばitertools.ifilter(predicate, iterator)は、イテレータの要素のうち関数predicate()がTrueを返すものをすべて返し、itertools.repeat(obj, N)はobjを N 回返します。 このモジュールにはほかにも多くの関数があります。 詳細はパッケージのリファレンス文書を参照してください。 (Raymond Hettinger による貢献です。)mathmodule の 2 つの新規関数degrees(rads)とradians(degs)は、ラジアンと度の間の変換を行います。mathモジュールのmath.sin()やmath.cos()などは常にラジアンでの入力が必要です。math.log()関数には底を指定するオプショナルの base 引数が追加されていて、eと10でない底の対数を計算するのが簡単になりました。 (Contributed by Raymond Hettinger.)Several new POSIX functions (
getpgid(),killpg(),lchown(),loadavg(),major(),makedev(),minor(), andmknod()) were added to theposixmodule that underlies theosmodule. (Contributed by Gustavo Niemeyer, Geert Jansen, and Denis S. Otkidach.)osモジュールの*stat()系の関数が、タイムスタンプの秒未満の部分を返せるようになりました。 このようなタイムスタンプは、time.time()が返す値と同様に浮動小数点数で表します。テストの結果、タイムスタンプが浮動小数点数だと正常に動作しなくなるアプリケーションがあることが分かりました。 互換性のため、
stat_resultのタプルインターフェースを使う場合、タイムスタンプは整数で表します。 名前付きフィールド (Python 2.2 で導入された機能) を使う場合も、os.stat_float_times()を呼んで浮動小数点数を返すようにしない限り、タイムスタンプは引き続き整数で表します。>>> os.stat("/tmp").st_mtime 1034791200 >>> os.stat_float_times(True) >>> os.stat("/tmp").st_mtime 1034791200.6335014
Python 2.4 では、浮動小数点数を返すのがデフォルトとなります。
アプリケーション開発者は、使用するすべてのライブラリが浮動小数点数のタイムスタンプを正しく扱える場合、またはタプル API を使っている場合に限り、この機能を有効にしてください。 使用する場合は、個々の使用箇所で有効にしようとせず、アプリケーション全体で有効にしてください。
optparseモジュールに新たなコマンドライン引数パーサが追加されました。これはオプション値を特定の Python 型に変換することが出来、また、自動的に使用例メッセージを生成します。詳細はこのドキュメントの続くセクションを参照して下さい。古く、一度も文書化されなかった
linuxaudiodevモジュールが非推奨となり、新しい版がossaudiodevという名前で追加されました。 OSS サウンドドライバーは Linux 以外のプラットフォームでも使えるため、モジュール名が変更されました。 インターフェースにもさまざまな整理や更新が行われています。 (Greg Ward と Nicholas FitzRoy-Dale による貢献です。)実行中のプラットフォームについての色々な特性を決定する数多くの関数を含む、新規
platformモジュールが追加されました。アーキテクチャ、CPU タイプ、Windows の OS バージョンや Linux ディストリビューションのバージョンなどを取得できます。(Contributed by Marc-André Lemburg.)pyexpatモジュールが提供するパーサーオブジェクトで、必要に応じて文字データをバッファリングできるようになりました。 これにより、文字データハンドラーの呼び出し回数が減り、性能が向上します。 パーサーオブジェクトのbuffer_text属性をTrueにすると、バッファリングが有効になります。randomモジュールにsample(population, k)関数が加わりました。 population は母集団の要素を含むシーケンスまたはxrangeオブジェクトです。sample()は母集団から k 個の要素を、選んだ要素を母集団に戻さずに選びます。 k にはlen(population)以下の値を指定できます。 例えば次のようになります。>>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn'] >>> random.sample(days, 3) # 3 個の要素を選ぶ ['St', 'Sn', 'Th'] >>> random.sample(days, 7) # 7 個の要素を選ぶ ['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn'] >>> random.sample(days, 7) # もう一度 7 個選ぶ ['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th'] >>> random.sample(days, 8) # 8 個は選べない Traceback (most recent call last): File "<stdin>", line 1, in ? File "random.py", line 414, in sample raise ValueError, "sample larger than population" ValueError: sample larger than population >>> random.sample(xrange(1,10000,2), 10) # 10000 未満の奇数を 10 個選ぶ [3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195]
randomが C で実装された新しいアルゴリズムのメルセンヌ・ツイスタを使うようになりました。これは以前のアルゴリズムよりも高速で、より広く研究されています。(All changes contributed by Raymond Hettinger.)
readlineモジュールにも、get_history_item()、get_current_history_length()、redisplay()という新しい関数が加わりました。rexecモジュールとBastionモジュールは廃止となり、インポートしようとするとRuntimeErrorで失敗します。 新スタイルクラスによって、rexecが提供する制限付き実行環境から抜け出す新たな方法が生まれましたが、修正に関心を持つ人も、その時間がある人もいません。rexecを使うアプリケーションは、ほかのものを使うように書き直してください。(Python 2.2 や 2.1 を使い続けてもアプリケーションが安全になるわけではありません。 それらのバージョンの
rexecモジュールにも既知のバグがあります。 繰り返しますが、rexecを使っているなら、直ちに使用をやめてください。)rotorモジュールは、使用している暗号化アルゴリズムが安全とは考えられないため、非推奨となりました。 暗号化が必要なら、別途入手できる Python 用 AES モジュールのいずれかを使ってください。shutilモジュールにmove(src, dest)が追加されており、これはファイルまたはディレクトリを新しい場所へ再帰的に移動します。signalに高度な POSIX シグナル処理のサポートが加わりましたが、プラットフォームによらず確実に動作させることができないと分かり、再び削除されました。socketモジュールがタイムアウトをサポートするようになりました。ソケットオブジェクトのsettimeout(t)メソッドに t 秒を与えることで行えます。これに続くソケット操作が t 秒を超えて完了しない場合には操作は中断し、socket.timeout例外を投げます。オリジナルのタイムアウト実装は Tim O'Malley によりなされました。Michael Gilfix がこれを Python
socketモジュールに統合し、長い長いレビューに導きました。コードがチェックインされたのち、Guido van Rossum はそれを部分的に書き換えました。(これは協調的開発プロセスの好例です。)Windows での
socketモジュールの Secure Sockets Layer (SSL) サポートが始まりました。C の
PYTHON_API_VERSIONマクロの値が、Python レベルでもsys.api_versionとして公開されました。 新しいsys.exc_clear()関数を呼び出すと、現在の例外を消去できます。新モジュール
tarfileで tar 形式のアーカイブファイルの読み書きが出来ます。 (Contributed by Lars Gustäbel.)新しい
textwrapモジュールには、テキストの段落を含む文字列を折り返す関数が含まれています。wrap(text, width)関数は文字列を受け取り、指定した幅以下の行に分割したテキストのリストを返します。fill(text, width)関数は、各行が指定した幅以下に収まるように整形した一つの文字列を返します。 (想像のとおり、fill()はwrap()をもとに作られています。) 例えば次のようになります。>>> import textwrap >>> paragraph = "Not a whit, we defy augury: ... more text ..." >>> textwrap.wrap(paragraph, 60) ["Not a whit, we defy augury: there's a special providence in", "the fall of a sparrow. If it be now, 'tis not to come; if it", ...] >>> print textwrap.fill(paragraph, 35) Not a whit, we defy augury: there's a special providence in the fall of a sparrow. If it be now, 'tis not to come; if it be not to come, it will be now; if it be not now, yet it will come: the readiness is all. >>>
このモジュールには、実際の折り返し処理を実装した
TextWrapperクラスも含まれています。TextWrapperクラスとwrap()関数、fill()関数は、整形を細かく調整するための追加のキーワード引数に対応しています。 詳細はモジュールの文書を参照してください。 (Greg Ward による貢献です。)threadモジュールとthreadingモジュールに、対応するdummy_threadモジュールとdummy_threadingモジュールが加わりました。 これらはスレッドをサポートしないプラットフォーム向けに、threadモジュールのインターフェースを何もしない形で実装しています。 目的は、スレッドに対応するものの、動作にはスレッドを 必要としない モジュールを、先頭に次のコードを置くだけで簡単に書けるようにすることです。try: import threading as _threading except ImportError: import dummy_threading as _threading
この例では、使用するモジュールが本物の
threadingモジュールとは限らないことを明示するため、モジュール名を_threadingとしています。 スレッドがサポートされているかどうかにかかわらず_threadingの関数やクラスを使えるので、if文が不要になり、コードが少し明快になります。 このモジュールは、マルチスレッドのコードをスレッドなしで動かす魔法ではありません。 別のスレッドが返ることや何かを行うことを待つコードは、単に永久に停止したままになります。timeモジュールのstrptime()関数は長いこと混乱の元でした。それがプラットフォームの C 関数strptime()を使い、異なったプラットフォームごとに時折おかしなバグを持っていたからです。Brett Cannon は pure Python で、全てのプラットフォームで全く同じに振舞うように書き直した実装を寄稿しました。新規モジュール
timeitは、Python コードの断片 (スニペット) を実行するのにかかる時間を計測します。ファイルtimeit.pyは直接コマンドラインから実行出来ますし、モジュールのTimerクラスをインポートして直接使うことも出来ます。以下に、空の Unicode 文字列を追加することによって 8 ビット文字列を Unicode に変換するのとunicode()関数を使うのとでいずれが高速なのかを把握するための短い例をお見せします:import timeit timer1 = timeit.Timer('unicode("abc")') timer2 = timeit.Timer('"abc" + u""') # 3 回計測する print timer1.repeat(repeat=3, number=100000) print timer2.repeat(repeat=3, number=100000) # 私のノートパソコンでの出力: # [0.36831796169281006, 0.37441694736480713, 0.35304892063140869] # [0.17574405670166016, 0.18193507194519043, 0.17565798759460449]
Tixモジュールに色々バグ修正がなされ、Tix パッケージの現在バージョンに更新されました。Tkinterモジュールがスレッドを有効化した Tcl で動作するようになりました。Tcl のスレッドモデルは、ウィジットはそれが作られたスレッドからのみアクセスされることを必要とします。ほかのスレッドからのアクセスは Tcl を混乱させます。ある特定の Tcl インターフェイスでは、Tkinterはウィジットがコマンドの纏め上げによって異なるスレッドからアクセスされる際に、正しいスレッドに向けて結果を待つことで自動的にこれを避けるようになりました。それ以外のインターフェイスでは自動で処理は出来ませんが、Tkinterはそのようなアクセス時に最低でもそれが問題とわかるよう例外を送出するようになっています。この変更についての詳細な説明は https://mail.python.org/pipermail/python-dev/2002-December/031107.html をみてください。(Implemented by Martin von Löwis.)_tkinterを介した Tcl メソッド呼び出しは今では文字列だけを返すのではありません。代わりに Tcl は対応する Python の等価なオブジェクトに変換されたオブジェクトを返します。Python に等価なものがなければ_tkinter.Tcl_Objで包んで返します。この振る舞いはtkappオブジェクトのwantobjects()メソッドで制御出来ます。(ほとんどの Tkinter アプリケーションがそうするように)
Tkinterモジュールを通して_tkinterを使う際、この機能は常に有効になります。これは互換性の問題を引き起こさないはずです。 Tkinter は可能な場合には文字列を Python 型に常に変換していたからです。何か非互換性を見つけたら古い振る舞いに戻せます。最初の
tkappオブジェクトを生成する前にTkinterモジュールのwantobjects変数に偽をセットしてください:import Tkinter Tkinter.wantobjects = 0
ここで説明した変更によって何かアプリケーションの破壊があれば、バグとして報告してください。
UserDictモジュールに新しくDictMixinクラスが追加されました。既に最小限のマッピングインターフェースを持っているクラスのために、全ての辞書メソッドを定義します。これは、shelveモジュール内のクラスのような、辞書に置換可能である必要があるクラスの記述を大幅に単純化します。クラスがメソッド
__getitem__(),__setitem__(),__delitem__(),keys()を定義している場合にはいつでも、スーパークラスとして mix-in を追加すると完全な辞書インターフェースになります。例えば:>>> import UserDict >>> class SeqDict(UserDict.DictMixin): ... """リストを使って実装した辞書風のオブジェクト。""" ... def __init__(self): ... self.keylist = [] ... self.valuelist = [] ... def __getitem__(self, key): ... try: ... i = self.keylist.index(key) ... except ValueError: ... raise KeyError ... return self.valuelist[i] ... def __setitem__(self, key, value): ... try: ... i = self.keylist.index(key) ... self.valuelist[i] = value ... except ValueError: ... self.keylist.append(key) ... self.valuelist.append(value) ... def __delitem__(self, key): ... try: ... i = self.keylist.index(key) ... except ValueError: ... raise KeyError ... self.keylist.pop(i) ... self.valuelist.pop(i) ... def keys(self): ... return list(self.keylist) ... >>> s = SeqDict() >>> dir(s) # ほかの辞書メソッドも実装されていることを確認 ['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__', '__init__', '__iter__', '__len__', '__module__', '__repr__', '__setitem__', 'clear', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keylist', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'valuelist', 'values']
(Contributed by Raymond Hettinger.)
xml.dom.minidomの DOM 実装で、DOM ノードのtoxml()メソッドとtoprettyxml()メソッドに省略可能なエンコーディング引数を渡すと、指定したエンコーディングの XML を出力できるようになりました。xmlrpclibモジュールが、 Python のNoneのような nil データを処理するための XML-RPC 拡張をサポートするようになりました。 nil 値は XML-RPC 応答のアンマーシャルでいつでもサポートされます。Noneを含んだリクエストを生成するためには、Marshallerのインスタンスを生成する際に allow_none パラメータに真を与えなければなりません。新規モジュール
DocXMLRPCServerは、セルフ-ドキュメンティング XML-RPC サーバを書くのに使えます。実際のところをみるためにはデモモード (つまりプログラムとして) 実行してみてください。ウェブブラウザを RPC サーバに向ければ pydoc スタイルのドキュメントを生成します。xmlrpclib をサーバに向ければ実際のメソッドを呼び出せます。(Contributed by Brian Quinlan.)internationalized domain names (RFC 3454, 3490, 3491, 3492) のサポートが追加されました。Unicode ドメイン名とその名前の ASCII 互換エンコーディング (ACE=ASCII-compatible encoding) の間の変換をするのに "idna" エンコーディングを使用出来ます:
>{}>{}> u"www.Alliancefrançaise.nu".encode("idna") 'www.xn--alliancefranaise-npb.nu'
socketモジュールも、C ライブラリに渡す前に Unicode ホスト名を ACE バージョンに透過的に変換するように拡張されています。httplibやftplibのようなホスト名を扱うモジュールも Unicode ホスト名をサポートしています;httplibは HTTPHostヘッダをドメイン名の ACE 版を使って送信します。urllibは URL のpath部分が ASCII のみである限り、非 ASCII ホスト名を持つ Unicode URL をサポートしますこの変更の実装のために、
stringprepモジュール、mkstringprepツール、punycodeエンコーディングが追加されました。
日付時刻型¶
タイムスタンプとして使うのに相応しい日付と時刻の型が datetime モジュールとして追加されました。これら型は異なるカレンダであるとか多くの洒落た機能をサポートはせずに、時刻表現の基礎だけに集中するものです。
3 つの基礎となるクラスがあり、 date は年・月・日を表現し、 time は時・分・秒を、 datetime が date と time の両方の属性すべてを持ちます。また、 timedelta は 2 つの時刻の差を表現し、タイムゾーンのロジックは抽象クラス tzinfo から派生したクラスにより実装されます。
date と time のインスタンスは、datetime.date(year=1972, month=10, day=15) のようにコンストラクターへキーワード引数を渡すか、用意されたいずれかのクラスメソッドを使って作成できます。
例えばクラスメソッド today() は、現在のローカルな日付を返します。
構築後の日付時刻クラスのインスタンスは全て immutable です。オブジェクトから書式文字列を生成する数多くのメソッドがあります:
>>> import datetime as dt
>>> now = dt.datetime.now()
>>> now.isoformat()
'2002-12-30T21:27:03.994956'
>>> now.ctime() # date と datetime だけで使用可能
'Mon Dec 30 21:27:03 2002'
>>> now.strftime('%Y %d %b')
'2002 30 Dec'
replace() メソッドは、date または datetime インスタンスの一つ以上のフィールドを変更した、新しいインスタンスを返します。
>>> d = dt.datetime.now()
>>> d
datetime.datetime(2002, 12, 30, 22, 15, 38, 827738)
>>> d.replace(year=2001, hour=12)
datetime.datetime(2001, 12, 30, 12, 15, 38, 827738)
>>>
インスタンスは比較可能で、ハッシュ出来、文字列に変換出来ます (結果は isoformat() メソッドのものと同じです)。 date と datetime はお互いに減算演算が可能で、 timedelta インスタンスを加算することも出来ます。最も大きな不足機能としては、文字列を解析して date や datetime へ戻すための標準ライブラリサポートはありません。(---訳注: 2 点。「比較可能」の意味は 2.3 から 2.4 で意味が変わっています。2.4 で date と datetime の比較は出来なくなりました。2.3 では出来ていました。文字列からの datetime 構築は 2.5 で strptime() が追加されています。---)
さらに詳しい情報については、モジュールのリファレンスドキュメントを参照してください。 (Contributed by Tim Peters.)
optparse モジュール¶
getopt モジュールはコマンドライン引数の単純な解析を提供しています。新規に追加された optparse モジュール (元々 Optik と呼ばれていたものです) は Unix の慣習に従ったもっと念入りなコマンドライン解析を行い、自動的に --help のための出力をし、異なったオプションに対して異なったアクションを実行出来ます。 (---訳注: 2.7 以降は optparse よりも新しい argparse を使ってください。---)
OptionParser インスタンスを作ることから始め、プログラムのオプションがどんなであるかそれに対して教えてやります:
import sys
from optparse import OptionParser
op = OptionParser()
op.add_option('-i', '--input',
action='store', type='string', dest='input',
help='set input filename')
op.add_option('-l', '--length',
action='store', type='int', dest='length',
help='set maximum length of output')
コマンドラインの解析は parse_args() メソッドを呼び出すことで行います
options, args = op.parse_args(sys.argv[1:])
print options
print args
これは、全てのオプションの値を含んだオブジェクトと残った引数を含む文字列リストを返します。
色々な引数でこのスクリプトを実行すれば、あなたの期待するように動きます。この例での length 引数が自動的に整数に変換されることに注目してください。
$ ./python opt.py -i data arg1
<Values at 0x400cad4c: {'input': 'data', 'length': None}>
['arg1']
$ ./python opt.py --input=data --length=4
<Values at 0x400cad2c: {'input': 'data', 'length': 4}>
[]
$
ヘルプメッセージはあなたのために自動生成されます:
$ ./python opt.py --help
usage: opt.py [options]
options:
-h, --help show this help message and exit
-iINPUT, --input=INPUT
set input filename
-lLENGTH, --length=LENGTH
set maximum length of output
$
さらに詳しいことはモジュールのドキュメントを参照して下さい。
Optik は Getopt SIG の読者からの示唆を受けてGreg Ward により書かれました。
Pymalloc: 特殊化されたオブジェクトアロケータ¶
Pymalloc は Vladimir Marangozov により書かれ Python 2.1 で追加された、特殊化されたオブジェクトアロケータです。Pymalloc は典型的な Python プログラムでのアロケーションのパターンにおいて、システムの malloc() よりも高速で省メモリであることを意図したものです。このアロケータは C の malloc() 関数を大きなメモリプールを得るのに使い、それより小さなメモリ要求はこれらプールで実現しています。
2.1 と 2.2 ではこの機能は実験的な位置付けでありデフォルトでは有効ではありませんでした。これを有効にするには Python コンパイル時に configure スクリプトに --with-pymalloc オプションを明示的に与える必要がありました。2.3 では pymalloc はさらに拡張され、また、デフォルトで有効になりました。逆にこれを無効にするのに --without-pymalloc を与える必要があります。
この変更は Python で書いたコードからは見えませんが、 pymalloc は C 拡張内のバグを露にするかもしれません。C 拡張の著者は pymalloc を有効にしてテストすべきです。というのも、ある種の正しくないコードが実行時にコアダンプしうるからです。
問題を起こすとりわけ一般的な誤りが一つあります。Python の C API 内には数多くのメモリアロケーション関数がありますが、これは以前は単に C ライブラリの malloc() と free() への別名であり、何かの間違いでミスマッチな関数呼び出しをしても、誤りは気付かれないものでした。今回のこのオブジェクトアロケータを有効化すると、これら関数は malloc() と free() への別名ではまったくなくて、メモリ解放に誤った関数を呼び出すとコアダンプし得ます。例えば PyObject_Malloc() を使って獲得したメモリは free() ではなく PyObject_Free() を使って解放する必要があります。Python に含まれるいくつかのモジュールがまさにこれに抵触し、修正の必要がありました。間違いなく多くのサードパーティモジュールが同じ問題を抱えているでしょう。
この変更の一環として、メモリアロケーションのためのこんがらかった複数インターフェイスが統合されて 2 つの API ファミリになりました。一方のファミリで獲得されたメモリは他方の関数で操作されることは許されません。一方のファミリはメモリの塊を獲得するためのもので、もう一方は Python オブジェクトの獲得に特殊化されたものです。
何某かの区別のないメモリの塊を獲得・解放するのには「生メモリ」ファミリを使います:
PyMem_Malloc(),PyMem_Realloc(),PyMem_Free().「オブジェクトメモリ」ファミリは上述の pymalloc 機構へのインターフェイスであり、多数の「小さな」獲得をするための特化がされています:
PyObject_Malloc(),PyObject_Realloc(),PyObject_Free().Python オブジェクトの獲得と解放には「オブジェクト」ファミリ
PyObject_New,PyObject_NewVar,PyObject_Del()を使います。
Tim Peters による多大な仕事のおかげで、 2.3 の pymalloc はデバッグ機能も提供しています。これはメモリの上書き、二重解放に関して、拡張モジュールとインタプリタ自身について検出出来ます。このサポートを有効にするには configure スクリプトにオプション --with-pydebug を与えて Python インタプリタをデバッグバージョンとしてコンパイルしてください。
拡張の著者のために、Python 2.3 のソースとともにヘッダファイル Misc/pymemcompat.h が配布されています。これは Python 拡張に 2.3 インターフェイスでのメモリ獲得を使えるようにするもので、1.5.2 以降の全てのバージョンに対してコンパイル可能です。Python のソース配布物からファイルをコピーして、あなたの拡張ソースにバンドル出来ます。
参考
- https://hg.python.org/cpython/file/default/Objects/obmalloc.c
pymalloc 実装に関する完全な詳細については Python ソースコード内の
Objects/obmalloc.cファイルの先頭のコメントを参照してください。上のファイルへのリンクは python.org の SVN ブラウザを指しています。
ビルドならびに C API の変更¶
Python のビルド過程と C API の変更は以下の通りです:
ガーベージコレクションで使われている循環の検出実装が安定であることがわかったため、必須とすることになりました。Python をこれなしでコンパイルすることはもう出来ません。 configure スクリプトの
--with-cycle-gcスイッチは削除されました。Python がオプショナルでシェアドライブラリ (
libpython2.3.so) としてビルド可能になりました。Python の configure スクリプトに--enable-sharedオプションを与えることで可能です。 (Contributed by Ondrej Palkovsky.)マクロ
DL_EXPORTとDL_IMPORTが非推奨となっています。Python コアが一般的にマクロPyAPI_FUNCとPyAPI_DATAを使うのに対し、Python 拡張モジュールの初期化関数が新規マクロPyMODINIT_FUNCを使って宣言されなければならなくなりました。configure スクリプトに
--without-doc-stringsオプションを与えることで、ビルトイン関数とモジュールが docstring を持たないインタプリタとしてコンパイル出来るようになりました。これは Python の実行形式ファイルを 10% 小さくしますが、もちろん Python ビルトインのヘルプが取得できないことにもなります。 (Contributed by Gustavo Niemeyer.)PyArg_NoArgs()マクロが非推奨となったので、これを使っているコードは修正しなければなりません。Python 2.2 以降ではメソッド定義テーブルでは引数を持たず、引数チェックを省けることを示すのにMETH_NOARGSフラグが使えます。2.2 以前の Python バージョンとの互換性が重要な場合にはPyArg_ParseTuple(args, "")を代わりに使えますが、METH_NOARGSを使うより遅いです。PyArg_ParseTuple()に符号なし整数の色々なサイズのためのフォーマット文字が追加されました: unsigned char のためのB, unsigned short int のためのH, unsigned int のためのI, unsigned long long のためのK。新規関数
PyObject_DelItemString(mapping, char *key)がPyObject_DelItem(mapping, PyString_New(key))の速記法として追加されました。ファイルオブジェクトの内部文字列バッファの管理が変更されて、必要な場合には指数関数的に増やすようになりました。
Lib/test/test_bufio.py内のベンチマークテストの結果での速度向上は大幅なものです (ある一つの計測では 57 秒から 1.7 秒になりました)。メソッドの
PyMethodDef構造体でMETH_CLASSまたはMETH_STATICフラグを設定することにより、C 拡張型にクラスメソッドや静的メソッドを定義できるようになりました。Python は Expat XML パーサのソースコードのコピーを丸抱えするようになり、これにより Expat のシステムのバージョンやローカルにインストールされたものへの依存がなくなっています。
拡張モジュールで型オブジェクトを動的に割り当てている場合は、
__module__属性と__name__属性に関する規則の変更に注意してください。 要するに、型の辞書に'__module__'キーが含まれるようにする必要があります。 型名の最後のピリオドより前の部分をモジュール名にする方法では、もはや期待した結果が得られません。 詳細は API リファレンスかソースコードを読んでください。
ポート特有の変更¶
Support for a port to IBM's OS/2 using the EMX runtime environment was merged
into the main Python source tree. EMX is a POSIX emulation layer over the OS/2
system APIs. The Python port for EMX tries to support all the POSIX-like
capability exposed by the EMX runtime, and mostly succeeds; fork() and
fcntl() are restricted by the limitations of the underlying
emulation layer. The standard OS/2 port, which uses IBM's Visual Age compiler,
also gained support for case-sensitive import semantics as part of the
integration of the EMX port into CVS. (Contributed by Andrew MacIntyre.)
MacOS では、後方互換性を改善するため、ほとんどの toolbox モジュールが弱いリンクを使うようになりました。 これにより、現在の OS バージョンに一つのルーチンがないだけでモジュールの読み込みが失敗することはなくなりました。 代わりに、そのルーチンを呼び出したときに例外が送出されます。 (Jack Jansen による貢献です。)
Python のソース配布物の Misc/RPM/ ディレクトリにある RPM spec ファイルが、2.3 に合わせて更新されました。
(Sean Reifschneider による貢献です。)
そのほか、AtheOS (http://www.atheos.cx/)、GNU/Hurd、OpenVMS でも Python がサポートされるようになりました。
その他の変更と修正¶
いつものように、たくさんのほかの改善とバグフィックスがソースツリー全体に渡って散らばっています。CVS 変更ログを検索すると、Python 2.2 から 2.3 にかけて適用されたパッチは 523、バグ修正は 514 ありました。いずれも少なく見積もって、です。
ほかの、さらに特筆すべき変更のいくつかを挙げます:
環境変数
PYTHONINSPECTをセットしておくと、Python インタプリタが Python プログラム実行後に対話モードに入ります。これは Python を-iで起動するのと同じです。環境変数は Python インタプリタ実行前にセットするか、Python プログラムのその実行の一部としてセットすることが出来ます。regrtest.pyスクリプトで「foo を除く全てのリソース」とする手段が出来ました。-uオプションにリソース名を渡すのにハイフン ('-') を前置すると「このリソースを除く」ことを意味します。例えば '-uall,-bsddb' はbsddbを除く全てのリソースを有効にするのに使えます。ドキュメントのビルドに使われるツールは今では Unix 同様に Cygwin でも動作します。
SET_LINENO命令コード (opcode) は削除されました。彼方の昔に戻れば、この命令コードはトレースバック内で行番号を生成し、トレース関数をサポートするのに必要でした (例えばpdbのために)。Python 1.5 より、トレースバック内の行番号は "python -O" で働くための異なったメカニズムを用いて計算で求められてきました。2.3 のためには Michael Hudson がトレース関数を呼ぶのに決定する似た方法を実装しましたので、SET_LINENOの必要性は完全になくなりました。Python コードから何か異なる結果を見つけるのは、
-Oなしで Python を実行する際のわずかなスピードアップを別とすれば、困難かもしれません。フレームオブジェクトの
f_linenoフィールドにアクセスしている C 拡張は、代わりにPyCode_Addr2Line(f->f_code, f->f_lasti)を呼び出すべきです。これは以前の Python バージョンでも "python -O" のもとでコードが動作するのにも望ましい効果を持つでしょう。気の利いた新機能としては、トレース関数は、今ではフレームオブジェクトの
f_lineno属性を、次に実行される行に変更してセットします。pdbデバッガにはこの新機能の恩恵を受けてjumpコマンドが追加されています。 (Implemented by Richie Hindle.)
Python 2.3 への移植¶
このセクションでは前述の変更により必要となるかもしれないコードの変更を列挙します:
yieldは今では常にキーワードです。変数名として使っていたならば、別の名前を選ぶ必要があります。文字列 X と Y について、
X in Yは X が一文字以上の場合でも動作するようになりました。int()型コンストラクタは、文字列や浮動小数点数を整数に収める際、それがとても大き場合にOverflowErrorを投げるのではなく長整数を返すようになっています。8 ビット文字を含んだ Unicode 文字列をソースコードに埋め込む場合、ファイルのエンコーディング (UTF-8, Latin-1, あるいはほか何か) を、ファイルの先頭のコメントに宣言しなければなりません。 PEP 263: ソースコードのエンコーディング を参照してください。
_tkinterを介した Tcl メソッド呼び出しは今では文字列だけを返すのではありません。代わりに Tcl は対応する Python の等価なオブジェクトに変換されたオブジェクトを返します。Python に等価なものがなければ_tkinter.Tcl_Objで包んで返します。0xffffffffのような大きな値の 8 進、16 進リテラルでFutureWarningが発行されます。2.3 ではこれは 32 ビットの値に格納されて結果は負の値になりますが、Python 2.4 ではこれは正の長整数になります。この警告の修正をする方法が少しだけあります。本当に正の値が欲しいのであれば
Lをリテラルの最後に付けて下さい。32 ビット分だけの下位ビットセットで 32 ビット整数を取り出したいのであれば、また、~(1 << 31)のような式を使ってきたのであれば、おそらく全ビットをセットすることから始めて上位ビットをクリアするのが最も簡明です。例えば最上位ビット (ビット 31) を単にクリアするには0xffffffffL &~(1L<<31)と書けます。(---訳注: 2 点。Python 3 サポートを検討するならばLは付けないように。2.4 以降は警告もなしに長整数になりますし。もう一点はこのパラグラフ全体について。根本的に警告への対処の話をしてるようで後半はほとんど本質でない話をしているので意味不明な文章になっています。本当に 2.3 を使わなければならないのでない限り、この文章を真面目に理解しようとしなくとも良いと思います(本質的な措置はLを付けることしかない、2.3 では)。---)__debug__に代入することでアサーションを無効にすることは出来なくなりました。Distutils の
setup()関数に depends のような色々な新しいキーワード引数が追加されています。Distutils の古いバージョンでは未知のキーワードを渡すと処理を中断してしまいます。新旧で動作させなければならないのであれば、setup.py内でget_distutil_options()関数の有無をチェックし、それらをサポートするバージョンの Distutils でのみ新しいキーワード引数を使うようにしてください:from distutils import core kw = {'sources': 'foo.c', ...} if hasattr(core, 'get_distutil_options'): kw['depends'] = ['foo.h'] ext = Extension(**kw)
Noneを変数名に使うとSyntaxWarning警告を出すようになっています。Python と一緒に含まれるモジュールで定義される拡張型の名前にモジュール名と
'.'が型名の頭に付くようになっています。
謝辞¶
著者は提案の申し出や修正、様々なこの記事の草稿の助けをしてくれた以下の人々に感謝します: Jeff Bauer, Simon Brunning, Brett Cannon, Michael Chermside, Andrew Dalke, Scott David Daniels, Fred L. Drake, Jr., David Fraser, Kelly Gerber, Raymond Hettinger, Michael Hudson, Chris Lambert, Detlef Lannert, Martin von Löwis, Andrew MacIntyre, Lalo Martins, Chad Netzer, Gustavo Niemeyer, Neal Norwitz, Hans Nowak, Chris Reedy, Francesco Ricciardi, Vinay Sajip, Neil Schemenauer, Roman Suzi, Jason Tishler, Just van Rossum.