11.01.2015

Type Assertion Decorator in Python

Python: 型チェックのデコレータ

 

Python は動的型付けの言語だが、抽象的なライブラリを書こうとすればどうしても型チェックの需要が生じる。

  • PyContracts は非常に良さそうなライブラリだが、独自のクラスには対応していない模様。
  • なので、車輪の再発明と知りつつも自前で実装してみた。

 

コード

 

インストール

mog-commons-python の一部として実験的にリリースしている。

pip install mog-commons

inspect#getcallargs をバックポートしたので、Python 2.6 / 2.7 / 3.2 / 3.3 / 3.4 / 3.5 の全てで動く。

 

使い方

関数定義と一緒に @types デコレータを指定するだけ。

  • 1個以下の可変長引数として、戻り値の型を指定 (省略も可能)
  • 名前付き引数として、パラメータ名=型 と制約を定義
  • ListOf, DictOf などを使えば、コレクションの要素の型もチェックできる
  • チェックに失敗したら、TypeError が発生
>>> from mog_commons.types import *

>>> @types(float, x=int, y=float, z=ListOf(int))
... def f(x, y, z):
...     return x * y + sum(z)
...

>>> f(1, 2, 3)
TypeError: y must be float, not int.

>>> f(1, 2.0, 3)
TypeError: z must be list(int), not int.

>>> f(1, 2.0, [3, 4])
9.0

戻り値だけのチェックも可能。

>>> @types(bool)
... def g(x):
...     return x
...

>>> g(3)
TypeError: must return bool, not int.

>>> g(True)
True

簡便のため、Python バージョンに透過的な String, Unicode, Option も定義した。
可変長引数、名前付き引数をチェックする場合は以下のようにする。

>>> @types(args=VarArg(String), kwargs=KwArg(int))
... def h(*args, **kwargs):
...     return 'ok'
...

>>> h('abc', 5, a=123, b=456)
TypeError: args must be tuple((basestring|str)), not tuple.

>>> h('abc', 'def', a=123, b=456)
'ok'

実際にどの要素の型が異なっているのか、までは表示していない。

 

これで、Typesafe Python にまた一歩近づいた。

0 件のコメント:

コメントを投稿