有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
有没有像isiterable这样的方法?到目前为止,我找到的唯一解决办法就是打电话
hasattr(myObj, '__iter__')
但我不确定这是否万无一失。
当前回答
你可以试试这个:
def iterable(a):
try:
(x for x in a)
return True
except TypeError:
return False
如果我们可以创建一个迭代它的生成器(但从不使用生成器,以免占用空间),那么它就是可迭代的。听起来像是"废话"一类的事。为什么首先需要确定一个变量是否可迭代?
其他回答
你可以试试这个:
def iterable(a):
try:
(x for x in a)
return True
except TypeError:
return False
如果我们可以创建一个迭代它的生成器(但从不使用生成器,以免占用空间),那么它就是可迭代的。听起来像是"废话"一类的事。为什么首先需要确定一个变量是否可迭代?
在Python <= 2.5中,你不能也不应该——iterable是一个“非正式的”接口。
但是从Python 2.6和3.0开始,你可以利用新的ABC(抽象基类)基础设施以及一些内置的ABC,这些ABC在collections模块中可用:
from collections import Iterable
class MyObject(object):
pass
mo = MyObject()
print isinstance(mo, Iterable)
Iterable.register(MyObject)
print isinstance(mo, Iterable)
print isinstance("abc", Iterable)
现在,这是否可取,或者是否有效,只是一个惯例的问题。正如你所看到的,你可以将一个不可迭代的对象注册为Iterable——它将在运行时引发一个异常。因此,isinstance获得了一个“新的”含义——它只是检查“声明的”类型兼容性,这在Python中是一个很好的方法。
另一方面,如果你的对象不能满足你所需要的接口,你会怎么做?举个例子:
from collections import Iterable
from traceback import print_exc
def check_and_raise(x):
if not isinstance(x, Iterable):
raise TypeError, "%s is not iterable" % x
else:
for i in x:
print i
def just_iter(x):
for i in x:
print i
class NotIterable(object):
pass
if __name__ == "__main__":
try:
check_and_raise(5)
except:
print_exc()
print
try:
just_iter(5)
except:
print_exc()
print
try:
Iterable.register(NotIterable)
ni = NotIterable()
check_and_raise(ni)
except:
print_exc()
print
如果对象不满足您的期望,则抛出TypeError,但如果已经注册了正确的ABC,则检查将毫无用处。相反,如果__iter__方法可用,Python将自动识别该类的object为Iterable。
如果你只是期望一个可迭代对象,遍历它,然后忘记它。另一方面,如果您需要根据输入类型执行不同的操作,那么您可能会发现ABC基础结构非常有用。
你可以检查__len__属性,而不是检查__iter__属性,它是由每个python内置可迭代对象实现的,包括字符串。
>>> hasattr(1, "__len__")
False
>>> hasattr(1.3, "__len__")
False
>>> hasattr("a", "__len__")
True
>>> hasattr([1,2,3], "__len__")
True
>>> hasattr({1,2}, "__len__")
True
>>> hasattr({"a":1}, "__len__")
True
>>> hasattr(("a", 1), "__len__")
True
由于显而易见的原因,不可迭代对象不会实现这一点。但是,它不会捕获没有实现它的用户定义迭代对象,也不会捕获生成器表达式,而iter可以处理生成器表达式。但是,这可以在一行中完成,并且为生成器添加一个简单的或表达式检查将解决这个问题。(注意,写入type(my_generator_expression) == generator会抛出NameError。请参考这个答案。)
你可以从类型中使用GeneratorType: >>>导入类型 > > >类型。GeneratorType <类“发电机”> >>> gen = (i for i in range(10)) >>> isinstance(gen, types.GeneratorType) 真正的 ——utdemir接受的回答
(这对于检查是否可以在对象上调用len非常有用。)
我一直不明白为什么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对象)
在我的脚本中,我经常发现定义一个可迭代函数很方便。 (现在合并了Alfe建议的简化):
import collections
def iterable(obj):
return isinstance(obj, collections.Iterable):
因此,您可以测试任何对象是否具有非常可读的可迭代形式
if iterable(obj):
# act on iterable
else:
# not iterable
就像你对可调用函数所做的那样
编辑:如果你安装了numpy,你可以简单地做: 简单地说是什么
def iterable(obj):
try: iter(obj)
except: return False
return True
如果没有numpy,可以简单地实现这段代码或上面的代码。