このサイトについて

もっと知りたいPython3000 - 言語仕様,組み込み関数,クラスへの変更

もっと知りたいPython3000 - 言語仕様,組み込み関数,クラスへの変更

Python 3000の新機能についてお知らせする連載も3回目。今回は言語仕様,組み込み関数,クラスへの変更などについての変更点についてまとめています。

http://gihyo.jp/dev/feature/01/python3000/0003

Python 3000では,一貫性を増すための仕様変更だけでなく,言語をより便利にする変更も多く行われています。

Function Annotations(関数注記)はおもしろいですね。関数につけるドキュメント文字列のように,引数や返り値にドキュメンテーションを加えることができる機能です。引数の後にコロンをつけて,文字列を表記します。

 def func(arg1:"this arg is for brabra"):
    ...

コロンのあとはPythonの式として評価されます。文字列リテラルだけでなく,Pythonの式ならなんでも置くことができます。コロンの後は関数オブジェクトが持つアトリビュートに,引数をキーとした辞書として格納されます。

このことを利用すると,引数の型チェックを手軽に実行できます。たとえば,引数の型を制限するために,型オブジェクトを指定するとします。こんな感じ。

 def func(arg1:int, arg2:str):
     ...

このような関数と,以下のように定義したargcheckをデコレータとして組み合わせると,引数の型チェックが行えます。関数定義の直前に「@argcheck」と書いておくわけですね。

 #!/usr/bin/env python3.0
 
 import inspect
 
 def getargvalue(fargs, argname, in_args, in_kwargs):
     """
     関数の引数リストを受け取り,引数名から与えられた引数を得る
     """
     # まずキーワード引数に与えられた引き数名があるかしらべ,あったら返す
     if argname in in_kwargs:
         return in_kwargs[argname]
     # 得た関数名を使って引数を調べる
     if argname in fargs:
         regdict=dict(zip(fargs, in_args))
         if argname in regdict:
             return regdict[argname]
     # TODO:デフォルト引数,Keyword only argumentなどについて対応する
     raise ValueError("no such argument: %s" % argname)
 
 def argcheck(func):
     """
     Python 3.0から追加されたFunction Annotationsを使い
     キーワードの型を調べるデコレータ
     """
     # 引数として受け取った関数オブジェクトを関数ローカルな変数に保存
     func=func
     # getfullargspecを使って関数に定義された引数のリストなどを得る
     (fargs, fvarargs, fvarkw, fdefaults, fkwonlyargs,
            fkwonlydefaults, fannotations)=inspect.getfullargspec(func)
     def checkarguments(*in_args, **in_kwargs):
         """
         引数をチェックして指定された型かどうかを調べる
         型が違ったら例外を発生,すべての引数の型があっていたら関数を呼び出す
         """
         for name in fargs:
             # 引き数名から引数を得る
             v=getargvalue(fargs, name, in_args, in_kwargs)
             # annotationsに記載された型指定を得る
             t=fannotations[name]
             if not isinstance(v, t):
                 raise ValueError("The argument '%s' for function '%s'"
                                  "should be %s" % (name, func.__name__, t))
         func(*in_args, **in_kwargs)
     return checkarguments
 
 if __name__ == '__main__':
     @argcheck
     def some_func(arg1:int, arg2:str):
         """
         テスト用の関数
         """
         print("some_func : arg1=%s, arg2=%s" % (arg1, arg2))
     
     # これはOK
     some_func(1, "2")
     # 例外が出る,なぜなら2番目の引数が求められているstrでなくintだから
     some_func(1, 2)

もちろん,このコードはPython 3.0でしか動きません。 関数定義の仕様には,Function Annotationsの他にKeyword only argumentsなども追加されています。これにあわせて,inspectモジュールにもいくつか関数が追加されています。

深く見てみると,Python 3.0はすごく面白いですね。リリースがとても楽しみです:-)。

2010-08-27 04:46