如何键入提示参数或isinstance
检查必须可迭代的对象并与len
一起使用?我假设几乎所有具有长度的对象都是可迭代的,所以这实际上是关于什么类型(如果有的话)表示实现__len__
的对象。
def n_and_list(x: ???):
return len(x), [y for y in x]
不是typing.Iterable
或collections.Iterable
,因为对于没有长度的内容,例如zip
,这些都是正确的。
In [1]: from typing import Iterable
In [2]: isinstance(zip([]), Iterable)
Out[3]: True
In [3]: from collections import Iterable
In [4]: isinstance(zip([]), Iterable)
Out[4]: True
In [5]: len(zip([]))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-27-86d411a5426c> in <module>()
----> 1 len(zip([]))
TypeError: object of type 'zip' has no len()
它不是typing.Sequence
或collections.Sequence
,因为对于有长度的东西,如字典键和numpy数组,这些都是错误的。
In [6]: from typing import Sequence
In [7]: isinstance({}.keys(), Sequence)
Out[7]: False
In [8]: from numpy import asarray
In [9]: isinstance(asarray([]), Sequence)
Out[9]: False
In [10]: from collections import Sequence
In [11]: isinstance({}.keys(), Sequence)
Out[11]: False
In [12]: from numpy import asarray
In [13]: isinstance(asarray([]), Sequence)
Out[13]: False
它不是iterable
或iter
,因为它们不是类型。它不是list
或tuple
,因为它们太窄了。
答案 0 :(得分:2)
def n_and_list(x: collections.Sized):
return len(x), [y for y in x]
或者对于您的情况,因为您希望它具有__len__
并且可以迭代:
import typing
import collections
def n_and_list(x: typing.Union[collections.Sized, collections.Iterable]):
return len(x), [y for y in x]
可悲的是,正如下面提到的评论所述,目前还没有typing.Intersection
来保证两者的存在。
答案 1 :(得分:2)
如果您不包含typing.Collection
,则可以使用__contains__
:
class Collection(Sized, Iterable, Container):
__slots__ = ()
@classmethod
def __subclasshook__(cls, C):
if cls is Collection:
return _check_methods(C, "__len__", "__iter__", "__contains__")
return NotImplemented
如果你这样做,只需删除对SizedIterable
__contains__
就可以轻松实现。
class SizedIterable(Sized, Iterable):
__slots__ = ()
@classmethod
def __subclasshook__(cls, C):
if cls is SizedIterable:
return _check_methods(C, "__len__", "__iter__")
return NotImplemented