いくつかのインターフェイスを記述するために、抽象基底クラスを使用してPythonの型注釈を試しています。可能なタイプの*args
および**kwargs
に注釈を付ける方法はありますか?
たとえば、関数への適切な引数がint
または2つのint
sであることをどのように表現しますか? type(args)
はTuple
を与えるので、私の推測では型にUnion[Tuple[int, int], Tuple[int]]
として注釈を付けることでしたが、これは機能しません。
from typing import Union, Tuple
def foo(*args: Union[Tuple[int, int], Tuple[int]]):
try:
i, j = args
return i + j
except ValueError:
assert len(args) == 1
i = args[0]
return i
# ok
print(foo((1,)))
print(foo((1, 2)))
# mypy does not like this
print(foo(1))
print(foo(1, 2))
Mypyからのエラーメッセージ:
t.py: note: In function "foo":
t.py:6: error: Unsupported operand types for + ("Tuple" and "Union[Tuple[int, int], Tuple[int]]")
t.py: note: At top level:
t.py:12: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:14: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 2 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
Mypyは、呼び出し自体にTuple
があることを期待しているため、関数呼び出しに対してmypyがこれを好まないことは理にかなっています。解凍後の追加も、私には理解できないタイプミスを与えます。
*args
および**kwargs
の賢明なタイプにどのように注釈を付けますか?
可変位置引数(*args
)および可変キーワード引数(**kw
)の場合、oneそのような引数の期待値のみを指定する必要があります。
Type Hints PEPの 任意の引数リストとデフォルトの引数値セクション から:
任意の引数リストにも型注釈を付けることができるため、定義は次のようになります。
def foo(*args: str, **kwds: int): ...
許容され、それは、例えば、以下のすべてが有効なタイプの引数を持つ関数呼び出しを表すことを意味します:
foo('a', 'b', 'c') foo(x=1, y=2) foo('', z=0)
したがって、次のようにメソッドを指定する必要があります。
def foo(*args: int):
ただし、関数が1つまたは2つの整数値しか受け入れられない場合は、*args
をまったく使用せず、1つの明示的な位置引数と2番目のキーワード引数を使用する必要があります。
def foo(first: int, second: Optional[int] = None):
現在、関数は実際には1つまたは2つの引数に制限されており、指定する場合は両方とも整数でなければなりません。 *args
alwaysは0以上を意味し、タイプヒントによってより具体的な範囲に制限することはできません。
前の回答への短い追加として、Python 2ファイルでmypyを使用し、注釈の代わりにコメントを使用して型を追加する必要がある場合、args
およびkwargs
の型の前に*
および**
それぞれ:
def foo(param, *args, **kwargs):
# type: (bool, *str, **int) -> None
pass
これはmypyによって以下と同じものとして扱われます。Python 3.5バージョンのfoo
:
def foo(param: bool, *args: str, **kwargs: int) -> None:
pass
これを行う適切な方法は @overload
を使用することです
from typing import overload
@overload
def foo(arg1: int, arg2: int) -> int:
...
@overload
def foo(arg: int) -> int:
...
def foo(*args):
try:
i, j = args
return i + j
except ValueError:
assert len(args) == 1
i = args[0]
return i
print(foo(1))
print(foo(1, 2))
@overload
を追加したり、実際の実装に注釈を入力したりしないでください。これは最後に来る必要があります。
@overload スタブファイルの外側 のサポートを取得するには、typing
とmypyの両方の新しいバージョンが必要です。
また、これを使用して、どの引数タイプがどの戻りタイプに対応するかを明示する方法で、返される結果を変えることができます。例えば。:
from typing import Tuple, overload
@overload
def foo(arg1: int, arg2: int) -> Tuple[int, int]:
...
@overload
def foo(arg: int) -> int:
...
def foo(*args):
try:
i, j = args
return j, i
except ValueError:
assert len(args) == 1
i = args[0]
return i
print(foo(1))
print(foo(1, 2))