Return a non iterator from __iter__

后端 未结 4 1032
离开以前
离开以前 2021-01-03 14:14
class test(object):
    def __init__(self):
        pass
    def __iter__(self):
        return \"my string\"

o = test()
print iter(o)

Why does th

4条回答
  •  猫巷女王i
    2021-01-03 14:36

    str is an iterable but not an iterator, subtle but important difference. See this answer for an explanation.

    You want to return an object with __next__ (or just next if py2) which is what str returns when is iterated.

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

    str does not implement __next__

    In [139]: s = 'mystring'
    
    In [140]: next(s)
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
     in ()
    ----> 1 next(s)
    
    TypeError: 'str' object is not an iterator
    

    However calling iter returns the iterator, which is what looping calls:

    In [141]: next(iter(s))
    Out[141]: 'm'
    

    You get the same problem returning anything without a __next__ (or next in py2) method

    You can use a generator, which itself has __iter__ that returns 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']
    

    Or a class where you implement __next__ yourself, like this class similar to the one on the Ops post (you also have to handle StopIteration which stops the loop)

    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
    

提交回复
热议问题