从__iter__返回一个非迭代器

时间:2018-01-06 05:09:56

标签: python

class test(object):
    def __init__(self):
        pass
    def __iter__(self):
        return "my string"

o = test()
print iter(o)

为什么会产生回溯?

$ python iter_implement.py
Traceback (most recent call last):
  File "iter_implement.py", line 9, in <module>
    print iter(o)
TypeError: iter() returned non-iterator of type 'str'

我希望__iter__在这种情况下只返回字符串。何时以及为什么检测到返回的对象不是迭代器对象?

4 个答案:

答案 0 :(得分:6)

cloneCurrentTree可迭代的,但不是迭代器,微妙但重要的区别。有关说明,请参阅此answer

您想要返回一个str的对象(如果是py2则只返回__next__),这是next在迭代时返回的内容。

str

def __iter__(self): return iter("my string") 未实施str

__next__

但是调用iter会返回迭代器,这就是循环调用:

In [139]: s = 'mystring'

In [140]: next(s)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-140-bc0566bea448> in <module>()
----> 1 next(s)

TypeError: 'str' object is not an iterator

在没有In [141]: next(iter(s)) Out[141]: 'm' (或py2中的__next__)方法的情况下返回任何内容时会遇到同样的问题

您可以使用一个生成器,它本身有next,返回__iter__

self

或者你自己实现def gen(): yield 'foo' gg = gen() gg is gg.__iter__() True gg.__next__() 'foo' class Something: def __iter__(self): return gen() list(Something()) ['foo'] 的类,就像这个类类似于Ops帖子上的那个类(你还必须处理停止循环的__next__

StopIteration

答案 1 :(得分:5)

可以通过添加 iter()调用来修复代码:

class test(object):
    def __init__(self):
        pass
    def __iter__(self):
        return iter("my string")

以下是一个示例运行:

>>> o = test()
>>> iter(o)
<iterator object at 0x106bfa490>
>>> list(o)
['m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g']

原始错误的原因是 __ iter __ 的API声称返回实际的迭代器。 iter()函数检查以确保合同得到满足。

注意,这种错误检查也发生在其他地方。例如, len()函数检查以确保 __ len __()方法返回一个整数:

>>> class A:
        def __len__(self):
            return 'hello'

>>> len(A())
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer

答案 2 :(得分:2)

__iter__魔术函数的目的是返回可以迭代(例如循环)的东西。最常见的解决方案是返回iter(something),其中something可以是列表,元组,集合,字典,字符串......我们可以迭代的任何内容。看一下这个例子:

class Band:
    def __init__(self):
        self.members = []

    def add_member(self, name):
        self.members.append(name)

    def __iter__(self):
        return iter(self.members)

if __name__ == '__main__':
    band = Band()
    band.add_member('Peter')
    band.add_member('Paul')
    band.add_member('Mary')

    # Magic of __iter__:
    for member in band:
        print(member)

输出:

Peter
Paul
Mary

在这种情况下,__iter__魔术函数允许我们循环遍历band,就像它是成员集合一样。这意味着在你的情况下,返回&#34;我的字符串&#34;不行。如果你想在&#34;我的字符串&#34;:

中列出字符列表
def __iter__(self):
    return iter("my string")  # ==> m, y, ' ', s, t, r, i, n, g

但是,如果你想返回一个包含单个元素的列表&#34;我的字符串&#34;,那么:

def __iter__(self):
    return iter(["my string"])

答案 3 :(得分:2)

回答您的具体问题。 Python2似乎检查是否存在.next类属性:

>>> class test(object):
...     next = None
...     def __iter__(self):
...         return self
... 
>>> print iter(test())
<__main__.test object at 0x7fcef75c2f50>

实例属性不会执行:

>>> class test(object):
...    def __init__(self):
...        self.next = None
...    def __iter__(self):
...        return self
... 
>>> print iter(test())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iter() returned non-iterator of type 'test'