HOME Python 書き込む

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_valuevalue に代入されるというバグが生じます。
これを回避するためには
(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:     #! /usr/bin/env python
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)) # look!
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 関数に
  1. equires, provides, および obsoletes キーワードが追加され、PKG-INFO ファイルを使って、 パッケージの依存関係を管理するようになりました。
  2. 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
を指定することで、標準パッケージのみをインポートするようにできます。この場合、ユーザ定義のパッケージを インポートする場合は以下のようにします。
# pkg.string から name1, name2 をインポートする場合
from .string import name1, name2

# pkg.string をインポートする場合
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
  1. next() メソッドが呼び出されると、i が counter の外に帰り、val には None が代入されます。
  2. send(x) メソッドが呼び出されると、x が counter の外に帰り、val に x が代入されます。
  3. close() メソッドが呼び出されると、generator は終了します。
  4. 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
上のコードでは、 詳しくは、
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. いろいろ

2.12.2. 最適化

2.13. モジュールの変更

2.14. Build and C API の変更

14 Build and C API Changes をご覧ください。

2.15. 以前のコードを Python2.5 に移植するために

15 Porting to Python 2.5 をご覧ください。

3. 終わりに

以上、長々と書きましたが、一般ユーザに関係ある点は、 の 4 点だと思います。

Python 2.5 にはかなり変更点があるので一度、 What's New in Python 2.5 by A.M. Kuchling (amk@amk.ca) をご覧になると良いと思います。 ここにはいろいろな例も載っているので、かなり有用な文書だと思います。