如何输入提示参数或isinstance检查必须可迭代且可使用的对象len?我假设几乎所有具有长度的对象都是可迭代的,所以这实际上是关于什么类型(如果有的话)代表实现__len__.
def n_and_list(x: ???):
return len(x), [y for y in x]
Run Code Online (Sandbox Code Playgroud)
事实并非如此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()
Run Code Online (Sandbox Code Playgroud)
它不是typing.Sequenceor 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
Run Code Online (Sandbox Code Playgroud)
不是iterable,或者iter因为那些不是类型。事实并非如此list,或者tuple因为这些范围太窄了。
def n_and_list(x: collections.Sized):
return len(x), [y for y in x]
Run Code Online (Sandbox Code Playgroud)
或者对于您的情况,因为您希望它具有__len__并且可迭代:
import typing
import collections
def n_and_list(x: typing.Union[collections.Sized, collections.Iterable]):
return len(x), [y for y in x]
Run Code Online (Sandbox Code Playgroud)
遗憾的是,正如下面的评论所提到的,typing.Intersection目前还不能保证两者都存在。