そのパラメーターの1つでlen
関数を使用し、パラメーターを反復する関数があります。これで、型にIterable
とSized
のどちらで注釈を付けるかを選択できますが、どちらもmypy
でエラーが発生します。
_from typing import Sized, Iterable
def foo(some_thing: Iterable):
print(len(some_thing))
for part in some_thing:
print(part)
_
与える
_error: Argument 1 to "len" has incompatible type "Iterable[Any]"; expected "Sized"
_
ながら
_def foo(some_thing: Sized):
...
_
与える
_error: Iterable expected
error: "Sized" has no attribute "__iter__"
_
この問題 で説明されているようにIntersection
がないので、ある種の混合クラスが必要です。
_from abc import ABCMeta
from typing import Sized, Iterable
class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
pass
def foo(some_thing: SizedIterable):
print(len(some_thing))
for part in some_thing:
print(part)
foo(['a', 'b', 'c'])
_
これは、foo
をlist
とともに使用するとエラーになります。
_error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
_
次の理由により、これはそれほど驚くべきことではありません。
_>>> SizedIterable.__subclasscheck__(list)
False
_
したがって、___subclasshook__
_を定義しました( docs を参照)。
_class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return Sized.__subclasscheck__(subclass) and Iterable.__subclasscheck__(subclass)
_
次に、サブクラスチェックが機能します。
_>>> SizedIterable.__subclasscheck__(list)
True
_
しかし、mypy
はまだ私のlist
について不満を言っています。
_error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
_
len
関数とパラメーターの反復の両方を使用する場合、型ヒントをどのように使用できますか? foo(cast(SizedIterable, ['a', 'b', 'c']))
のキャストは良い解決策ではないと思います。
Python3.6から、Collection
という新しいタイプがあります。 こちら を参照してください。
将来的にはProtocol
sが導入されます。それらはすでに typing_extensions
。 PEP 544 も参照してください。 Protocol
を使用すると、上記のコードは次のようになります。
from typing_extensions import Protocol
class SizedIterable(Protocol):
def __len__(self):
pass
def __iter__(self):
pass
def foo(some_thing: SizedIterable):
print(len(some_thing))
for part in some_thing:
print(part)
foo(['a', 'b', 'c'])
mypy
は文句を言わずにそのコードを受け取ります。しかし、PyCharmは言っています
タイプ 'SizedIterable'が必要ですが、 'List [str]'を取得しました
最後の行について。
リストまたはタプルのみを使用して、その要素にx[0]
のようにインデックスでアクセスする場合は、Sequence
from typing を使用する必要があります。