有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话

hasattr(myObj, '__iter__')

但我不确定这是否万无一失。


当前回答

我一直不明白为什么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对象)

其他回答

你可以试试这个:

def iterable(a):
    try:
        (x for x in a)
        return True
    except TypeError:
        return False

如果我们可以创建一个迭代它的生成器(但从不使用生成器,以免占用空间),那么它就是可迭代的。听起来像是"废话"一类的事。为什么首先需要确定一个变量是否可迭代?

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__。

如果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

到目前为止,我找到的最佳解决方案是:

Hasattr(obj, '__contains__')

它主要检查对象是否实现了in操作符。

优点(其他解决方案都不具备这三个优点):

它是一个表达式(工作为lambda,而不是try…变体除外) 它(应该)由所有可迭代对象实现,包括字符串(而不是__iter__) 适用于任何Python >= 2.5

注:

Python的“请求原谅,而不是允许”的哲学在例如,在一个列表中,你有可迭代对象和不可迭代对象,你需要根据它的类型区别对待每个元素(在try上处理可迭代对象,在except上处理不可迭代对象可以工作,但它看起来很丑,会误导人)时,就不会很好地工作了。 对于这个问题的解决方案,试图实际遍历对象(例如[x for x in obj])来检查它是否为可迭代对象,可能会导致对大型可迭代对象的显著性能损失(特别是如果你只需要可迭代对象的前几个元素,例如),应该避免

检查__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__可迭代的类。