Python 3.6型ヒントを使用して関数のデコレータを記述しようとしています。引数のディクショナリが型ヒントを尊重していることを確認し、問題の明確な説明でエラーが発生しない場合は、 HTTP APIに使用できます。
問題は、関数にUnion
タイプを使用するパラメーターがある場合、実行時に変数に対して変数をチェックできないことです。
たとえば、私はこの機能を持っています
_from typing import Union
def bark(myname: str, descr: Union[int, str], mynum: int = 3) -> str:
return descr + myname * mynum
_
できます:
_isinstance('Arnold', bark.__annotations__['myname'])
_
だがしかし:
_isinstance(3, bark.__annotations__['descr'])
_
Union
はisinstance
またはissubclass
と一緒に使用できないためです。
タイプオブジェクトを使用してそれをチェックする方法が見つかりませんでした。自分でチェックを実装しようとしましたが、_bark.__annotations__['descr']
_が_typing.Union[int, str]
_としてREPL=に表示されている間は、実行時に型のリストにアクセスできませんbark.__annotations__['descr'].__repr__()
を調べるという醜いハックを使用します。
この情報にアクセスする適切な方法はありますか?それとも、実行時に簡単にアクセスできないように意図的に意図されていますか?
__args__
Union
のTuple
を保持する "可能なコンテンツ:
>>> from typing import Union
>>> x = Union[int, str]
>>> x.__args__
(int, str)
>>> isinstance(3, x.__args__)
True
>>> isinstance('a', x.__args__)
True
__args__
引数はドキュメント化されていないため、「実装の詳細をいじる」と考えることができますが、repr
を解析するよりも良い方法のようです。
MSeifert( https://stackoverflow.com/a/45959000/743342 )による既存の受け入れられた回答は、Union
sを他のジェネリック型と区別せず、実行時に判別することは困難です型注釈がUnion
であるか、Mapping
のような他の一般的な型であるかは、パラメータ化されたUnion
でのisinstance()
およびissubclass()
の動作によるタイプ。
ジェネリック型には、それを作成するために使用された元のジェネリック型への参照が含まれる、文書化されていない__Origin__
属性があるようです。タイプアノテーションがパラメータ化されたUnion
であることを確認したら、ドキュメント化されていない__args__
属性を使用してタイプパラメータを取得できます。
>>> from typing import Union
>>> type_anno = Union[int, str]
>>> type_anno.__Origin__ is Union
True
>>> isinstance(3, type_anno.__args__)
True
>>> isinstance('a', type_anno.__args__)
True
typeguard
でインストールできるpip
モジュールを使用できます。関数check_argument_types
または関数デコレータ@typechecked
を提供します。ランタイムタイプチェックを実行する必要があります: https://github.com/agronholm/typeguard
from typing import Union
from typeguard import check_argument_types, typechecked
def check_and_do_stuff(a: Union[str, int]) -> None:
check_argument_types()
# do stuff ...
@typechecked
def check_decorator(a: Union[str, int]) -> None:
# do stuff ...
check_and_do_stuff("hello")
check_and_do_stuff(42)
check_and_do_stuff(3.14) # raises TypeError
別の理由で単一の変数の型をチェックする場合は、typeguardのcheck_type
関数を直接使用できます。
from typing import Union
from typeguard import check_type
MyType = Union[str, int]
check_type("arg", "string", MyType, None) # OK
check_type("arg", 42, MyType, None) # OK
check_type("arg", 3.5, MyType, None) # raises TypeError
この例では、"arg"
およびNone
引数は使用されていません。 check_type
関数はこのモジュールのパブリック関数として文書化されていないため、そのAPIは変更される可能性があることに注意してください。