特集

UNIX USER2005年2月号特別企画より転載:

2.4への機能強化で広がるPythonの世界 (3/4)

2005年01月24日 16時00分 更新

前のページ | 1 2 3 4 | 次のページ

関数やメソッドの修飾構文

 関数やメソッドの修飾構文の機能向上は、Python 2.4の拡張のうち、目玉ともいえる部分です。この構文については開発者メーリングリストにおいて、長期間にわたって議論が繰り返されました。関数やメソッドに対する修飾機能そのものはPython 2.2から存在していましたが、専用の構文は用意されていませんでした。

 たとえば、クラスメソッドを定義する場合、従来はリスト1のように記述していました。この方法はクラスの記述が複雑になったり、メソッドのコード量が増えると、メソッドの定義部分とクラスメソッドとしての登録部分が離れてしまい、可読性が低下する問題がありました。

リスト1 クラスメソッドを定義する場合の従来の記述例
class foo:
   def method(args):
       :
       :
   method = classmethod(method)

 Python 2.4では、「@」という記号を使って、メソッドを修飾する構文が提供され、リスト2のように書くことが可能になりました。この@を使った構文は、クラスメソッドを定義する場合以外にも、自由に使用できます。

リスト2 Python 2.4では、「@」という記号を使って、メソッドを修飾する構文が提供されている
class foo:
   @classmethod
   def method(args):
       :
       :

 実行例12では、関数オブジェクトにcreatedTimeという属性を作成し、その値として、時刻を代入する修飾用の関数createdTimeを定義しています。関数fooとbarを定義する際にこの修飾を指定しています。結果として、それぞれの関数オブジェクトにはcreatedTimeという属性が作られ、それを参照すれば定義された時刻が分かります。このような関数を修飾する関数のことをデコレータといいます。

実行例12 関数オブジェクトにcreatedTimeという属性を作成し、その値として時刻を代入する修飾用の関数createdTimeを定義している
>>> import time
>>> def createdTime(funcObj):
...     funcObj.createdTime = time.time()
...     return funcObj
...
>>> @createdTime
... def foo(x):
...     print x + 1
...
>>> @createdTime
... def bar(name):
...     print "Hello %s" % name
...
>>> foo.createdTime
1103025973.760793
>>> bar.createdTime
1103026042.8535249
>>> foo(10)
11
>>> bar("World")
Hello World

 ここで重要なのは、修飾用の関数が適用されるのは実行時ではなく、定義時である点です。つまり、デコレータによって複数の関数に共通したシグネチャを持たせる操作を簡単に記述できるようになったわけです。

 デコレータには引数を与えることもでき、これを利用するといろいろと面白いことができます。リスト3は関数の引数の型をチェックするデコレータの例です。実行結果は実行例13のようになり、正しく引数の型チェックが行われていることが分かります。

リスト3 関数の引数の型をチェックするデコレータの例
赤字の部分にマウスカーソルをあてると内容を確認できます

import math

def declareArgs(*argTypes):
 def checkArguments(func):
  assert func.func_code.co_argcount == len(argTypes)
  def wrapper(*args, **kwargs):
   pos = 1
   for (arg, argType) in zip(args, argTypes):
    assert isinstance(arg, argType), \
       "Value %r dose not match %s at %d" % (arg, argType, pos)
    pos += 1
   return func(*args, **kwargs)

  wrapper.func_name = func.func_name
  return wrapper

 return checkArguments


@declareArgs(float, float)
def calcDistance(x, y):
 return math.sqrt(x * x + y * y)

print calcDistance(3.14, 1.592)
print calcDistance(2.0, 4)



実行例13 リスト3の実行結果。正しく引数の型チェックが行われていることが分かる
$ /opt/Python-2.4/bin/python DecoratorTest.py
3.52052041607
Traceback (most recent call last):
  File "DecoratorTest.py", line 27, in ?
    print calcDistance(2.0, 4)
  File "DecoratorTest.py", line 11, in wrapper
    assert isinstance(arg, argType), \
AssertionError: Value 4 dose not match at 2

 また、この一連の動作はリスト4のようにコードを書いた場合とまったく同じです。リスト4で、print calcDistance(3.14, 1.592)を実行すると、実際に起動する関数本体はwrapper(*args, **kwargs)ということになります。wrapper関数の引数argsは(3.14, 1.592)になっています。この実引数がargTypesで与えられている型に対応しているかを順番にチェックし、すべて正しければ func(*args, **kwargs)が実行され、結果を返します。変数funcは、上位の関数checkArgumentsでオリジナルのcalcDistanceオブジェクトが代入されていますので、結果としてオリジナルのcalcDistance(3.14, 1.592)が実行されることになります。

リスト4 リスト3と同様の動作をするコード
def calcDistance(x, y):
    return math.sqrt(x * x + y * y)

checkArgFuncObj = declareArgs(float, float)
wrapperFuncObj = checkArgFuncObj(calcDistance)
calcDistance = wrapperFuncObj

 このような関数のカスタマイズは、従来も行えましたが、デコレータを使うことでさらに簡潔に記述できるようになったわけです。デコレータはこれ以外にも多くの利用法がありますので、研究してみると面白いと思います。

10進数演算モジュール

 Python 2.4から、10進数演算の機能を提供するDecimalモジュールが標準になりました。これで、1.1を10回足すと正しく11になる計算ができるようになりました(リスト5)。浮動小数点数による計算では、丸め誤差のため計算結果は11.0になりませんが、decimalを使った10進数計算では正しい結果が得られます。

リスト5 10進数演算の機能を提供するDecimalモジュールを利用すると、浮動小数点数を含む数値の10進数計算で正しい結果が得られる
>>> import decimal
>>> dnum = decimal.Decimal("1.1")
>>> dsum = decimal.Decimal("0")
>>> rnum = 1.1
>>> rsum = 0.0
>>> for i in range(10):
...   dsum = dsum + dnum
...   rsum = rsum + rnum
...
>>> rsum
10.999999999999998
>>> dsum
Decimal("11.0")
>>> str(dsum)
'11.0'

前のページ | 1 2 3 4 | 次のページ

[磯 蘭水,UNIX USER]

Copyright(c)2010 SOFTBANK Creative Inc. All rights reserved.




キャリアアップ



エンタープライズ・ピックアップ

news008.jpg クラウドがもたらす本当のメリット:日本のクラウド市場の現状とクラウドの価値へのフォーカス
クラウドに関する企業ユーザーの声は厳しい。それが何を意味するのかがいまだ分かりにくく、まして何を提供してどのような利便性が生まれるのかの説明がなされていないからである。クラウドがもたらす変化や体験を正しく伝え、理解されることが、本当のクラウドを企業へ推進することにつながるのである。

news008.jpg 点検 ストレスなきデジタル情報整理術:「残業ゼロ」に向けて社員の能力を引き出す方法――元トリンプ社長の吉越氏
業務の生産性向上や効率化などの課題を解決するには、ITの活用に加えて、社員が活力を維持できることも重要になる。ストレスのない働き方を実現していくためのポイントを、「残業ゼロの仕事術」で知られる元トリンプ・インターナショナル・ジャパン社長の吉越浩一郎氏に聞いた。

news040.jpg 戦略コンサルタントの視点:無料化するクラウド、潜む落とし穴
戦略コンサルティングファーム独ローランド・ベルガーに、情報システムの新たな姿について寄稿してもらう。4回目は、クラウドコンピューティングの落とし穴について解説する。

news013.jpg ITmedia リサーチインタラクティブ 第5回調査:Google Appsへの期待が鮮明に――変わる企業の情報共有基盤
電子メールやスケジュール管理などの機能を持つコミュニケーションツールの入れ替え時期が迫っている。10年前に導入した企業が約4割に上り、今後の導入においてはGoogle Appsへの期待が高まっている。ITmedia エンタープライズとITRが実施した読者調査から、企業の情報共有基盤に対するニーズの変化を明らかにする。

news011.jpg ドジっ娘リーダー奮闘記:年上の男の子
年功序列型の組織ではあまり存在しなかった立場と年齢の逆転が実力主義の現在では当たり前になり、若いリーダーが年上のメンバーとの関係に戸惑うことが多いようです。今日は年上のメンバーへの接し方を、しんこちゃん&春美ちゃんの新米リーダーペアとともに学びましょう。