有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
当前回答
我最近一直在研究这个问题。基于此,我的结论是,现在这是最好的方法:
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))来覆盖。
其他回答
检查__iter__适用于序列类型,但在Python 2中检查字符串会失败。我也想知道正确的答案,在那之前,这里有一种可能性(这也适用于字符串): 试一试: Some_object_iterator = iter(some_object) except TypeError as te: 打印(some_object, 'is not iterable')
内置iter检查__iter__方法,如果是字符串,则检查__getitem__方法。
另一种通用的python方法是假设一个可迭代对象,如果它在给定对象上不起作用,则会优雅地失败。Python术语表:
python编程风格,通过检查对象的方法或属性签名来确定对象的类型,而不是通过与某些类型对象的显式关系(“如果它看起来像鸭子,并且嘎嘎叫得像鸭子,那么它一定是鸭子。”)通过强调接口而不是特定的类型,设计良好的代码通过允许多态替换来提高其灵活性。duck类型避免使用type()或isinstance()进行测试。相反,它通常采用EAFP(请求原谅比请求许可更容易)风格的编程。
...
试一试: _ = (e代表my_object中的e) 除了TypeError: 打印my_object, 'is not iterable'
collections模块提供了一些抽象基类,允许询问类或实例是否提供特定的功能,例如: 从集合。abc import Iterable if isinstance(e, Iterable): # e是可迭代的
但是,这不会检查通过__getitem__可迭代的类。
我在这里找到了一个很好的解决方案:
isiterable = lambda obj: isinstance(obj, basestring) \
or getattr(obj, '__iter__', False)
有很多方法来检查一个对象是否可迭代:
from collections.abc import Iterable
myobject = 'Roster'
if isinstance(myobject , Iterable):
print(f"{myobject } is iterable")
else:
print(f"strong text{myobject } is not iterable")
有点晚了,但我问了自己这个问题,然后想到了一个答案。我不知道是不是有人发了这个。但本质上,我注意到所有可迭代类型的字典中都有__getitem__()。这是你不用尝试就能检查对象是否为可迭代对象的方法。(一语双关)
def is_attr(arg):
return '__getitem__' in dir(arg)
def is_iterable(x):
try:
0 in x
except TypeError:
return False
else:
return True
这将对所有可迭代对象说“是”,但对Python 2中的字符串说“不”。(例如,当递归函数可以接受字符串或字符串容器时,这就是我想要的。在这种情况下,请求原谅可能会导致模糊代码,最好先征求允许。)
import numpy
class Yes:
def __iter__(self):
yield 1;
yield 2;
yield 3;
class No:
pass
class Nope:
def __iter__(self):
return 'nonsense'
assert is_iterable(Yes())
assert is_iterable(range(3))
assert is_iterable((1,2,3)) # tuple
assert is_iterable([1,2,3]) # list
assert is_iterable({1,2,3}) # set
assert is_iterable({1:'one', 2:'two', 3:'three'}) # dictionary
assert is_iterable(numpy.array([1,2,3]))
assert is_iterable(bytearray("not really a string", 'utf-8'))
assert not is_iterable(No())
assert not is_iterable(Nope())
assert not is_iterable("string")
assert not is_iterable(42)
assert not is_iterable(True)
assert not is_iterable(None)
这里有许多其他策略会对字符串说“是”。如果你想的话就用吧。
import collections
import numpy
assert isinstance("string", collections.Iterable)
assert isinstance("string", collections.Sequence)
assert numpy.iterable("string")
assert iter("string")
assert hasattr("string", '__getitem__')
注意:is_iterable()会对bytes和bytearray类型的字符串说yes。
Python 3中的bytes对象是可迭代的True == is_iterable(b"string") == is_iterable("string".encode('utf-8')) Python 2和3中的bytearray对象是可迭代的True == is_iterable(bytearray(b"abc"))
O.P. hasattr(x, '__iter__')方法将对Python 3中的字符串说“是”,而在Python 2中对字符串说“否”(无论“或b”或u”)。感谢@LuisMasuelli注意到它也会让你在一个bug __iter__。