Python 2.5 の新機能
1. 初めに
2006 年 9 月 19 日に Python 2.5 がリリースされました。このバージョンではかなりいろいろな点が
改善され、ますます使いやすくなっています。
この文書では Python 2.5 の改善点を簡単に紹介したいと思います。
詳しく知りたい人は What's New in Python 2.5
をみてください。
2. Python 2.5 での変更点
2.1. 三項演算子
Python 2.5 から "三項演算子" が使えるようになりました。
今まで、Python には三項演算子が無かったので、単に条件によって代入される値を変えるために
if predicate:
value = then_value
else:
value = else_value
と書くのは冗長なので、簡潔に、
value = predicate and then_value or else_value
書くことがしばしばありました。しかしこの書き方には
then_value が偽として認識されるものだと else_value が value に代入されるというバグが生じます。
これを回避するためには
(value,) = predicate and (then_value,) or (else_value,)
のように変数をタプルでくくる必要がありました。
この書き方ではバグは無いのですが、一見不必要なタプルを用いる必要があり、かなりいけていません。
そこで、Python 2.5 からは
value = then_value if predicate else else_value
という記法を導入することによって条件による値の振り分けを簡潔に記述できるようになりました。
predicate, then_value, else_value の順番が C 言語
や、LISP
とは異なっていて若干混乱を招きそうですが、Perl や Ruby の if 節を後置する記法になれた人には受け入れやすいかもしれません。
2.2. 関数の部分適用
関数の部分適用とは、もともとの関数の一部の引数に値を与え、残りの引数をとる関数を生成する機能です。
Haskell などの関数型言語では良く使われる機能です。
以下に簡単な例を挙げます。
#! /usr/bin/env python
import functools
def add (a,b):
return a+b
if __name__=='__main__':
add_1 = functools.partial(add, b=1)
print "add_1 is a function that takes one argument. "
print "The function is produced by applying b=1 to the function \'add(a,b)\'"
print "add_1(10) = " + str(add_1(10))
この機能は意外と便利です。というのは、Python では関数のポインターを変数として扱えるので、高階関数を
用いることができるからです。ただし、引数として与えられる関数の引数の数は決まっているため、
うまく使わないとコードのモジュール化が促進されません。Python 2.4 までは、関数のクラスを用いて
この問題に対処していましたが、2.5 からは functools.partial が使えるので簡潔に記述することが
できます。
実用的な例として、Tkinter の Button ウィジェットを生成するとき指定する関数のポインター
があります。
ボタンを押すと実行する関数をキーワード引数 command に渡すのですが、この関数は引数無しの
関数でなければなりません。従って、似たような動作をするボタンをたくさん作るときは、
(Tkinter 入門) 関数のクラスを使ってクールなコードを書こう
に示すように、
関数のクラスを定義する必要がありました。Python 2.5 ではこれ
と同じことを行うプログラムが以下のように簡潔に書くことができます。
001:
002:
003: """
004: bg4.py
005:
006: Change Background of flower
007:
008: Oct 10 2006
009: """
010:
011:
012: import Tkinter as Tk
013: import functools
014:
015: FLOWER = 'nanohana3.gif'
016:
017:
018: BGS = [('aliceblue', '#F0F8FF'), ('azure', '#F0FFFF'), ('beige', '#F5F5DC'), \
019: ('cornsilk', '#FFF8DC'), ('khaki', '#F0E68C'), ('lightgreen', '#90EE90'), \
020: ('lightpink', '#FFB6C1'), ('lightskyblue', '#87CEFA'), ('palegreen', '#98FB98')]
021:
022:
023: class Frame(Tk.Frame):
024:
025: def __init__(self, master=None):
026: Tk.Frame.__init__(self, master)
027: self.master.title('select background')
028: f_button = Tk.Frame(self)
029: f_button.pack(side=Tk.LEFT, padx=5, pady=5)
030: self.flower = Tk.PhotoImage(file=FLOWER)
031: self.label = Tk.Label(self, image=self.flower, relief=Tk.RAISED, bd=3)
032: self.label.pack(side=Tk.RIGHT, padx =5)
033:
034: for name, code in BGS:
035: b = Tk.Button(f_button, text=name, bg=code, command=functools.partial(self.bg_change, color=code))
036: b.pack(fill=Tk.X)
037:
038: def bg_change(self, color):
039: self.label.configure(bg=color)
040:
041:
042:
043:
044: if __name__ == '__main__':
045: f = Frame()
046: f.pack()
047: f.mainloop()
38,39 行目で、color を引数にとるメソッド bg_change を定義します。それを 35 行目の Tk.Button を生成するときに、
これを部分適用して生成した引数なしのメソッドを command のパラメータとして渡します。
ここで示すように、関数部分適用を用いると、関数のクラスを定義するより簡潔に書ける場合が多くなります。
2.3. パッケージインストールの簡素化
setup 関数に
- equires, provides, および obsoletes キーワードが追加され、PKG-INFO ファイルを使って、
パッケージの依存関係を管理するようになりました。
- download_url キーワードによりパッケージのソースコードの場所を特定することができるようになりました。
この情報も PKG-INFO に記録され、必要なパッケージを自動でダウンロードするようになりました。
詳しくは、
PEP 314: Metadata for Python Software Packages v1.1 をみてください。
2.4. パッケージを検索するディレクトリの順番の変更
現在の仕様ではユーザが指定したパッケージディレクトリが、標準パッケージより先に検索されます。
従って、ユーザ指定パッケージディレクトリ (以下 pkg) に、標準パッケージと同じ名前のパッケージがあれば、
pkg にあるパッケージがインポートされます。例えば、pkg/string.py がある場合、標準の string パッケージではなく、
pkg.string がインポートされます。
Python 2.5 では
from __future__ import absolute_import
を指定することで、標準パッケージのみをインポートするようにできます。この場合、ユーザ定義のパッケージを
インポートする場合は以下のようにします。
from .string import name1, name2
from . import string
2.5. runpy モジュールの追加
-m コマンドラインオプションの代わりに runpy モジュールが追加されました。
詳しくは
をみてください。
2.6. 例外処理の改善: try/except/finally の同時使用
Python 2.4 では try/except または try/finally の組しか使えず、例外処理が不便でした。
Python 2.5 では、try/except/finally を同時に使うことができる様になったので、簡潔に例外処理を記述することができます。
コードは次のようになります。
try:
try_something ...
except Exception_1:
handler_1 ...
except Exception_2:
handler_2 ...
else:
do_something_unless_exception ...
finally:
this_is_always_done ...
まず、try_something が実行されます。Exception_1 が発生すると handler_1 が呼び出され、
最後に this_is_always_done が実行されます。
Exception_2 の場合も同様です。例外が発生しないと do_something_unless_exception が実行され、
最後に this_is_always_done が実行されます。
例外発生の有無にかかわらず実行したいことを finally に書いておくことにより、ファイルの閉じ忘れ
などを防ぐことをできます。
2.7. generator の追加機能
yield が値を返すように変更されました。
例えば以下の例では、
[gen.py]
001: def counter (max_count):
002: i=0
003: while i < max_count:
004: val = (yield i)
005: if val is not None:
006: i = val
007: else:
008: i += 1
- next() メソッドが呼び出されると、i が counter の外に帰り、val には None が代入されます。
- send(x) メソッドが呼び出されると、x が counter の外に帰り、val に x が代入されます。
- close() メソッドが呼び出されると、generator は終了します。
- throw(type, value=None, traceback=None) が呼び出されると、type の例外が送出され、generator は終了します。
実行例
>>> from gen import counter
>>> iter=counter(10)
>>> iter.next()
0
>>> iter.next()
1
>>> iter.next()
2
>>> iter.send(7)
7
>>> iter.next()
8
>>> iter.close()
>>> iter.next()
Traceback (most recent call last):
File "", line 1, in
StopIteration
2.8. with ステートメント
オブジェクトに __enter__ と __exit__ メソッドが定義されていると with ステートメントが使えます。
こんな感じで使います。
001: from __future__ import with_statement
002:
003: with file('some.txt', 'r') as f:
004: for line in f:
005: print line
上のコードでは、
- 3 行目で file の __enter__ メソッドが呼び出され、ファイルが f として開かれます。
- 4,5 行目の実行が終了すると __exit__ メソッドが呼び出され、ファイルが閉じます。
__exit__ メソッドには、例外が発生したときの処理を記述できます。
詳しくは、
8 PEP 343: The 'with' statement
をみてください。
2.9. Exception が '新しいクラス' になる
詳しくは、
9 PEP 352: Exceptions as New-Style Classes
をみてください。
2.10. インデックスに ssize_t を使う
今までの int の代わりに ssize_t をリストやタプルのインデックスに使用するようになりました。
これは 64-bit CPU への対応です。
詳しくは、
10 PEP 353: Using ssize_t as the index type
をみてください。
2.11. __index__ メソッドの追加
詳しくは、
11 PEP 357: The '__index__' method
をみてください。
2.12. その他
2.12.1. いろいろ
- 辞書型に __missing__ メソッドが追加されました。これは、key が見つからないときの挙動を既定します。
- partition(sep) と rpartition(sep) メソッドが 8-bit と Unicode の両方に追加されました。
- 文字列のメソッド、startswith() and endswith() が引数に文字列のタプルをとれるようになりました。
- min(), max() に比較のための関数を渡せるようになりました。
- 組み込み関数 any(), all() が追加されました。これはイテレータの要素をチェックするのに使用します。
- long integer を __hash__ メソッドの戻り値にすることができるようになりました。
- 文字コードの宣言無しで、ASCII 以外の文字を使うと syntax error になります。
- Unicode と比較できない ASCII コードを無理に比較しようとすると UnicodeWarning が発生します。
- コマンドラインオプション '-Wd' を指定すると __init__.py が無い場合 ImportWarning がでます。
- 空のクラスが可能になりました。
- 対話モードが若干変更されました。
2.12.2. 最適化
- 'set' の実装が変化し、メモリー消費量が減り、実行速度が若干向上しました。
- Unicode の処理が高速化されました。
- long(str, base) の実行速度が大幅に向上しました。
- struct モジュールの実行速度が向上しました。
- re モジュールの実行速度が若干向上しました。
- code generator が改良されました。
- 関数の呼び出しが早くなりました。
- Frame オブジェクトが若干小さくなりました。
- 例外処理が早くなりました。
- インポート処理が改良されました。
2.13. モジュールの変更
- audioop が a-LAW encoding をサポートするようになりました。u-LAW encoding のコードも改良されました。
- codecs が incremental codecs をサポートするようになりました。
- collection が defaultdict タイプを持つようになりました。このタイプは dict とほとんど同じであるが、
key が見つからない場合デフォルト値として空リストか 0 がセットされます。
どちらがセットされるかは、defaultdict(type) の引数で決まります。
type が list なら空リストを、 int なら 0 がセットされます。
これを使うと単語の数え上げが
awk 並に簡単にできます。
下のコードはargv[1] で与えられたファイルを開いて単語の出現回数をカウントし、
出現回数の多い順に表示するプログラムと実行例です。
[wc.py]
from __future__ import with_statement
import sys
from collections import defaultdict
if __name__=='__main__':
with file(sys.argv[1]) as f:
ls=[w.strip('\'\".,?!;:()') for w in f.read().lower().split()]
h=defaultdict(int)
for w in ls:
h[w]+=1
ls=h.items()
ls.sort(lambda p0,p1: cmp(p1[1],p0[1]))
for k,v in ls:
print "%s\t%d" % (k,v)
$python wc.py english.txt
the 239
to 190
you 153
a 131
of 128
that 89
is 84
..................
..................
- collection の deque オブジェクトに remove(value) メソッドが追加されました。
- contextlib モジュールが追加されました。
ここ
を参照して下さい。
- cProfile モジュールが追加されました。これは profile モジュールを C 言語で
実装したものです。profile よりオーバヘッドが少ないです。
- cvs モジュールが改良されました。
- datetime モジュールの datetime クラスに strptime(string, format) メソッドが追加されました。
これは string を format に基づいて parse して、時刻を得るメソッドです。
- difflib の SequenceMatcher.get_matching_blocks() が改良されました。
- doctest モジュールに SKIP オプションが加わりました。
- testfile() 関数と DocFileSuite クラスに encoding parameter が加わりました。
- email パッケージが version 4.0 になりました。
- fileinput モジュールがより柔軟になりました。
- gc モジュールが改良されました。
- heapq モジュールの nsmallest() と nlargest() 関数が比較のための関数をキーワードパラメターとしてとるようになりました。
- itertools.islice() 関数が start, stop 引数として None を受け付けるようになりました。
- locale モジュールの format() 関数が変更された。また、format_string() と currency() 関数が追加されました。
- mailbox モジュールが大幅に書き換えられました。
- Microsoft インストーラーを作成する msilib モジュールが追加されました。
- nis モジュールが改良されました。
- operator モジュールが改良されました。
- optparse モジュールが version1.5.1 になりました。
- os モジュールがいくらか変化しました。
- pdb が改良されました。
- pickle と cPickle が変更されました。
- pkgutil が改良されました。
- pybench が ools/pybench directory に加わりました。
- pyexpat がアップデートされました。
- regex モジュールと regsub モジュールが削除されました。
- lib-old ディレクトリが削除されました。
- rlcompleter が leadline に依存しなくなりました。
- SimpleXMLRPCServer と DocXMLRPCServer クラスが rpc_paths 属性を持つようになりました。
- socket モジュールが Linux 上で AF_NETLINK をサポートするようになりました。
- システムのシャドーパスワードにアクセスする spwd モジュールが追加されました。
- struct の実行速度が速くなりました。
- 2.5 からリポジトリを CVS から Subversion に変更しました。
- sys._current_frames() 関数が追加されました。
- tarfile が改良されました。
- threading が改良されました。
- unicodedata が version 4.1.0 にアップデートされました。
- RFC 4122 に基づいて UUID を生成する uuid モジュールが追加されました。
- weakref, webbrowser, xmlrpclib, zipfile, zlib モジュールが改良されました。
- 任意の shared library の関数を呼び出すための ctypes パッケージが追加されました。
- XML を処理するパッケージ xml.etree が追加されました。
- md5 と sha を統合して hashlib にしました。このモジュールで、SHA-224, SHA-256, SHA-384, and SHA-512 が
使用できるようになりました。
- sqlite3 パッケージ (sqlite wrapper) が追加されました。
- wsgiref パッケージ (Web Server Gateway Interface) が追加されました。
2.14. Build and C API の変更
14 Build and C API Changes をご覧ください。
2.15. 以前のコードを Python2.5 に移植するために
15 Porting to Python 2.5
をご覧ください。
3. 終わりに
以上、長々と書きましたが、一般ユーザに関係ある点は、
- 三項演算子が定義された。
- 例外処理が改良された。
- 関数の部分適用が可能になった。
- collection モジュールの defaultdict は便利だ。
の 4 点だと思います。
Python 2.5 にはかなり変更点があるので一度、
What's New in Python 2.5 by A.M. Kuchling (amk@amk.ca)
をご覧になると良いと思います。
ここにはいろいろな例も載っているので、かなり有用な文書だと思います。