从__iter__返回一个非迭代器

Ank*_*wal 1 python

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

o = test()
print iter(o)
Run Code Online (Sandbox Code Playgroud)

为什么这会追溯?

$ 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'
Run Code Online (Sandbox Code Playgroud)

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

sal*_*ise 6

str是一个可迭代但不是迭代器,微妙但重要的区别.请参阅此答案以获得解释.

你想要返回一个对象__next__(或者只是next当py2),这str是迭代时返回的对象.

def __iter__(self):
      return iter("my string")
Run Code Online (Sandbox Code Playgroud)

str 没有实现 __next__

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
Run Code Online (Sandbox Code Playgroud)

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

In [141]: next(iter(s))
Out[141]: 'm'
Run Code Online (Sandbox Code Playgroud)

没有__next__(或next在py2)方法返回任何东西你会遇到同样的问题

您可以使用生成器__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']
Run Code Online (Sandbox Code Playgroud)

或者你__next__自己实现的类,就像这个类类似于Ops帖子上的类(你还必须处理StopIteration停止循环)

class test:
    def __init__(self, somestring):
        self.s = iter(somestring)

    def __iter__(self):
        return self

    def __next__(self):
        return next(self.s) ## this exhausts the generator and raises StopIteration when done.

In [3]: s = test('foo')

In [4]: for i in s:
   ...:     print(i)
   ...:
f
o
o
Run Code Online (Sandbox Code Playgroud)


Ray*_*ger 5

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

class test(object):
    def __init__(self):
        pass
    def __iter__(self):
        return iter("my string")
Run Code Online (Sandbox Code Playgroud)

这是一个示例运行:

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

原始错误的原因是__iter__的API 声称返回实际的迭代器.在国际热核实验堆()函数进行检查,以确保履行合同.

注意,这种错误检查也发生在其他地方.例如,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
Run Code Online (Sandbox Code Playgroud)