web-dev-qa-db-ja.com

Pythonでのサイズ変更イテラブルのタイプヒント

そのパラメーターの1つでlen関数を使用し、パラメーターを反復する関数があります。これで、型にIterableSizedのどちらで注釈を付けるかを選択できますが、どちらも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'])
_

これは、foolistとともに使用するとエラーになります。

_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']))のキャストは良い解決策ではないと思います。

21
Benjamin

Python3.6から、Collectionという新しいタイプがあります。 こちら を参照してください。

8
Avision

将来的にはProtocolsが導入されます。それらはすでに typing_extensionsPEP 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]'を取得しました

最後の行について。

6
Benjamin

リストまたはタプルのみを使用して、その要素にx[0]のようにインデックスでアクセスする場合は、Sequence from typing を使用する必要があります。

1
hans