有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
当前回答
不是真的“正确”,但可以作为最常见的类型,如字符串,元组,浮动等快速检查…
>>> '__iter__' in dir('sds')
True
>>> '__iter__' in dir(56)
False
>>> '__iter__' in dir([5,6,9,8])
True
>>> '__iter__' in dir({'jh':'ff'})
True
>>> '__iter__' in dir({'jh'})
True
>>> '__iter__' in dir(56.9865)
False
其他回答
这是不够的:__iter__返回的对象必须实现迭代协议(即next方法)。请参阅文档中的相关部分。
在Python中,一个好的实践是“尝试并查看”而不是“检查”。
我一直不明白为什么python有callable(obj) -> bool,而没有iterable(obj) -> bool… 当然,hasattr(obj,'__call__')更容易,即使它更慢。
由于几乎所有其他答案都建议使用try/except TypeError,其中测试异常通常被认为是任何语言中不好的做法,这里是iterable(obj) -> bool的实现,我越来越喜欢并经常使用:
为了python 2,我将使用lambda来获得额外的性能提升… (在python 3中,你用什么来定义函数并不重要,def的速度与lambda大致相同)
iterable = lambda obj: hasattr(obj,'__iter__') or hasattr(obj,'__getitem__')
注意,这个函数对于带有__iter__的对象执行得更快,因为它不测试__getitem__。
大多数可迭代对象应该依赖于__iter__,而特殊情况下的对象则返回到__getitem__,尽管对于可迭代对象来说,这两者都是必需的。 (因为这是标准的,所以它也会影响C对象)
如果object是可迭代的,下面代码中的isiterable函数将返回True。如果不是iterable则返回False
def isiterable(object_):
return hasattr(type(object_), "__iter__")
例子
fruits = ("apple", "banana", "peach")
isiterable(fruits) # returns True
num = 345
isiterable(num) # returns False
isiterable(str) # returns False because str type is type class and it's not iterable.
hello = "hello dude !"
isiterable(hello) # returns True because as you know string objects are iterable
考虑到Python的duck类型,最简单的方法是捕捉错误(Python完全知道它期望从一个对象变成迭代器):
class A(object):
def __getitem__(self, item):
return something
class B(object):
def __iter__(self):
# Return a compliant iterator. Just an example
return iter([])
class C(object):
def __iter__(self):
# Return crap
return 1
class D(object): pass
def iterable(obj):
try:
iter(obj)
return True
except:
return False
assert iterable(A())
assert iterable(B())
assert iterable(C())
assert not iterable(D())
注:
如果异常类型相同,则区分对象是否不可迭代或已经实现了有bug的__iter__是无关紧要的:无论如何,您将无法迭代对象。 我想我理解你的担忧:如果我也可以依赖鸭类型来引发AttributeError,如果__call__没有为我的对象定义,那么callable如何作为检查存在,但这不是可迭代检查的情况? 我不知道答案,但你可以实现我(和其他用户)给出的函数,或者只是在你的代码中捕获异常(你在那部分的实现将像我写的函数一样——只要确保你将迭代器的创建与其余代码隔离开来,这样你就可以捕获异常并将其与另一个TypeError区分开来。
我最近一直在研究这个问题。基于此,我的结论是,现在这是最好的方法:
from collections.abc import Iterable # drop `.abc` with Python 2.7 or lower
def iterable(obj):
return isinstance(obj, Iterable)
上面的建议已经在前面,但普遍的共识是使用iter()会更好:
def iterable(obj):
try:
iter(obj)
except Exception:
return False
else:
return True
为了这个目的,我们在代码中也使用了iter(),但我最近开始越来越讨厌只有__getitem__被认为是可迭代的对象。在一个不可迭代对象中使用__getitem__是有正当理由的,因此上面的代码不能很好地工作。作为一个真实的例子,我们可以使用Faker。上面的代码报告它是可迭代的,但实际上试图迭代它会导致AttributeError(用Faker 4.0.2测试):
>>> from faker import Faker
>>> fake = Faker()
>>> iter(fake) # No exception, must be iterable
<iterator object at 0x7f1c71db58d0>
>>> list(fake) # Ooops
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/.../site-packages/faker/proxy.py", line 59, in __getitem__
return self._factory_map[locale.replace('-', '_')]
AttributeError: 'int' object has no attribute 'replace'
如果我们使用insinstance(),我们不会意外地认为Faker实例(或任何其他只有__getitem__的对象)是可迭代的:
>>> from collections.abc import Iterable
>>> from faker import Faker
>>> isinstance(Faker(), Iterable)
False
之前的回答评论说,使用iter()更安全,因为在Python中实现迭代的旧方法是基于__getitem__的,isinstance()方法不会检测到这一点。对于旧的Python版本,这可能是真的,但根据我非常详尽的测试,isinstance()现在工作得很好。isinstance()不起作用而iter()起作用的唯一情况是在使用Python 2时使用UserDict。如果这是相关的,可以使用isinstance(item, (Iterable, UserDict))来覆盖。