2009-01-26

Python 3.0 のアノーテーション

Python Code Reading でアノーテーションがちらりと話題になりました。関数定義で

def func(a: expr, b: expr, ...) -> expr

という記述の仕方ができる、というもの。で、こうやって書いた expr は関数オブジェクトの __annotations__ プロパティに辞書で格納されます。

>>> def foo(a:int, b:"hogehoge") -> str: pass
...
>>> foo.__annotations__
{'a': <class 'int'>, 'b': 'hogehoge', 'return': <class 'str'>}

この構文を function annotation というそうです。で、アノーテーションに書かれた式の値が辞書に入るだけで、別に Python が静的に型チェックをしてくれるというわけではないです。一般に Python 関数定義では戻り値の型をコンパイル時に特定することはできませんから。



じゃあ何に使うのかと言うと動的型チェックをテスト時や運用時にするとかでしょう。他にも PEP 3107 にはIDE で関数の引数や戻り値を表示させるとか、その他 inspection のアプリケーションっぽいことが挙げられています。



戻り値の型チェックは、こんな感じでしょうか。

>>> def check(func):
    def call_and_check(*args, **kw):
        result = func(*args, **kw)
        if not isinstance(result, func.__annotations__["return"]):
            raise TypeError
        else:
            return result
    return call_and_check       



@check
def foo(x:int) -> int:
    return x



print( foo(1) )
print( foo("1") )
... ... ... ... ... ... ... ... >>> ... ... ... >>> 1
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in call_and_check
TypeError

引数の型チェックは、ちょっと面倒ですね。*args に入ってくるのか、**kw に入ってくるのかの場合分けなんかが死ぬほど面倒くさそうです。継承されたメソッドがきちんと規約に合っているか、とかなら簡単にチェックできそうです。