![]() |
![]() |
![]() |
この文書では Python 2.5 の改善点を簡単に紹介したいと思います。 詳しく知りたい人は What's New in 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 節を後置する記法になれた人には受け入れやすいかもしれません。
#! /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 のパラメータとして渡します。
ここで示すように、関数部分適用を用いると、関数のクラスを定義するより簡潔に書ける場合が多くなります。
Python 2.5 では
from __future__ import absolute_importを指定することで、標準パッケージのみをインポートするようにできます。この場合、ユーザ定義のパッケージを インポートする場合は以下のようにします。
# pkg.string から name1, name2 をインポートする場合 from .string import name1, name2 # pkg.string をインポートする場合 from . import string
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 に書いておくことにより、ファイルの閉じ忘れ などを防ぐことをできます。
[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
>>> 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
001: from __future__ import with_statement 002: 003: with file('some.txt', 'r') as f: 004: for line in f: 005: print line上のコードでは、
詳しくは、 10 PEP 353: Using ssize_t as the index type をみてください。
これを使うと単語の数え上げが
awk 並に簡単にできます。
下のコードはargv[1] で与えられたファイルを開いて単語の出現回数をカウントし、
出現回数の多い順に表示するプログラムと実行例です。
[wc.py]
#! /usr/bin/env python 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])) # descending sort by frequency 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 .................. ..................
Python 2.5 にはかなり変更点があるので一度、 What's New in Python 2.5 by A.M. Kuchling (amk@amk.ca) をご覧になると良いと思います。 ここにはいろいろな例も載っているので、かなり有用な文書だと思います。
![]() |
![]() |
![]() |