Python 2.4の新しい機能の紹介 |
前口上が長くなりましたが、いよいよPython 2.4で新たに追加されたり、以前のバージョンから向上した機能のうち、プログラムを書くうえでとくに便利になったと思われる部分を、筆者の独断と偏見でチョイスしていきましょう。
以前のバージョンでは、モジュールとして提供されていた集合を表現するための機能が、Python 2.4では、集合を表現するためのsetという型として組み込まれました(実行例1、図1)。
これらの集合演算は組み込み型としてCで実装されており、高速に動作します。setにはこのほかにも、要素の追加や削除などのメソッドが存在し、集合の演算が非常に便利になりました。
実行例1 集合を表現するための型setの利用例 |
>>> a = set("hello world") >>> a set([' ', 'e', 'd', 'h', 'l', 'o', 'r', 'w']) >>> b = set("good bye") >>> 'w' in a True >>> a & b set([' ', 'e', 'd', 'o']) >>> a ^ b set(['b', 'g', 'h', 'l', 'r', 'w', 'y']) >>> a | b set([' ', 'b', 'e', 'd', 'g', 'h', 'l', 'o', 'r', 'w', 'y']) |
Python 2.4から、通常の整数型と多倍長整数型が統合され、シームレスに扱えるようになりました。たとえば、Python 2.3以前の場合、2の32ビット左シフトの結果は次のようにオーバーフローによって0となります。
>>> hex(2 << 32) '0x0' |
Python 2.4では、必要に応じて、整数は自動的に多倍長整数に変換されるようになりました。
>>> hex(2 << 32) '0x200000000L' |
これによって、大きな数を扱う演算について、型を意識してコードを書く手間が省けます。
Pythonには、リストを作成する場合に便利な、リスト内包表現という構文があります。たとえば下の例では、[1,2,3,4,5]という数列のうち偶数だけを取り出して、新しいリストを作成しています。
>>> [x for x in (1,2,3,4,5) if x % 2 == 0] [2, 4] |
この構文をうまく使うと、いままでfor、あるいはwhileとifを組み合わせて記述していた部分が簡潔に表現できます。リスト内包表現は便利な構文ですが、出力としてリストを作成しますので、その分メモリを必要とします。実行例2を実行すると、lstは5万個の要素を持つリストを指すことになります。
実行例2 lstは5万個の要素を持つリストを指すことになる |
>>> lst = [x for x in range(100000) if x % 2 == 0] |
つまり、大きな結果を返すリスト内包表現はメモリ効率が良くありません。Python 2.4では、このような問題を解決できるジェネレータ式という構文が追加されました(実行例3)。
実行例3 Python 2.4で追加された構文「ジェネレータ式」の例用例 |
>>> gen = (x for x in range(100000) if x % 2 == 0) >>> gen <generator object at 0x402db44c> |
これは、リスト内包表現の構文そのままで、囲む記号を「[]」から「()」に変更しただけです。この結果、作成されるオブジェクトはジェネレータ1個になります。ジェネレータにはnext()というメソッドがあり、このメソッドは呼ばれるたびに並びの要素を1つずつその場で生成して返します(実行例4)。つまり、並び全体を格納しておくメモリ領域が不要になり、リーズナブルに利用できるようになります。
実行例4 ジェネレータにはnext()というメソッドがあり、呼ばれるたびに並びの要素を1つずつその場で生成して返す |
>>> gen = (x for x in range(5) if x % 2 == 0) >>> gen.next() 0 >>> gen.next() 2 >>> gen.next() 4 >>> gen.next() Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration |
next()メソッドは、返す値がなくなるとStopIterationという例外を発生します。これは繰り返しを終了させる例外ですので、ジェネレータは実行例5のようにfor文の中で利用できます。
実行例5 ジェネレータをfor文の中で利用した場合 |
>>> gen = (x for x in range(5) if x % 2 == 0) >>> for i in gen: ... print i + 1, ... 1 3 5 |
Pythonには、以前から、名前をベースにした便利な文字列の置き換え機能が備わっています。実行例6のように、文字列中に「%(名前)データ型」という形式でプレースホルダーを書いておき、後から%演算子を使って埋め込むデータを流し込めます。しかし、この構文では流し込むデータ型を明示しなくてはならず、型が違う場合には実行例7のようにエラーになってしまいます。また、埋め込むべきデータがない場合もエラーになります(実行例8)。
実行例6 名前をベースにした文字列の置き換え機能 |
>>> import time >>> msg = "Hello %(name)s , it's %(hour)i o'clock." >>> msg % {"hour": time.localtime().tm_hour, "name": "James Random Hacker"} "Hello James Random Hacker , it's 20 o'clock. |
実行例7 文字列の置き換え機能を利用する際、型が違う場合にはエラーになる |
>>> msg % {"name": "James Random Hacker", "hour": "20"} Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: int argument required |
実行例8 埋め込むべきデータがない場合もエラーになる |
>>> msg % {"name": "James Random Hacker", "month": "12"} Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'hour' |
Python 2.4では、$と辞書を使った書式化を行える、より柔軟なTemplateクラスが追加されました。Templateクラスはstringモジュール内にあり、実行例9のように利用できます。このように、データ型に依存しない書き方ができるようになっています。
実行例9 Python 2.4で追加されたTemplateクラス |
>>> import string >>> msg = string.Template("Hello $name , it's $hour o'clock") >>> msg.substitute({"name": "James Random Hacker", "hour": time.localtime().tm_hour}) "Hello James Random Hacker , it's 20 o'clock" >>> msg.substitute({"name": "James Random Hacker", "hour": "01"}) "Hello James Random Hacker , it's 01 o'clock" |
substituteメソッドでは、埋め込むべきデータがない場合は実行例10のようにエラーになります。これを無視するには実行例11のようにsafe_substitute() メソッドを使います。このように存在しないデータについては、未処理のまま結果を返します。さらにこの結果を、再びstring.Template()でテンプレートにして、段階的に最終的な出力を作成していけるようになりました。
実行例10 substituteメソッドでは、埋め込むべきデータがない場合はエラーになる |
>>> msg.substitute({"name": "James Random Hacker", "month": "12"}) Traceback (most recent call last): File "<stdin>", line 1, in ? File "/opt/Python-2.4/lib/python2.4/string.py", line 172, in substitute return self.pattern.sub(convert, self.template) File "/opt/Python-2.4/lib/python2.4/string.py", line 162, in convert val = mapping[named] KeyError: 'hour' |
実行例11 実行例9のようなエラーを無視するにはsafe_substitute()メソッドを使う |
>>> msg.safe_substitute({"name": "James Random Hacker", "month": "12"}) "Hello James Random Hacker , it's $hour o'clock" |
Copyright(c)2010 SOFTBANK Creative Inc. All rights reserved.