Why does a class need __iter__() to return an iterator?

后端 未结 2 910
梦如初夏
梦如初夏 2021-01-31 00:40

Why does a class need to define __iter__() returning self, to get an iterator of the class?

class MyClass:
    def __init__(self):
        self.stat         


        
2条回答
  •  悲&欢浪女
    2021-01-31 01:23

    isn't that already done by the __new__() method

    Nope, __new__ is just another method, it doesn't automatically create __iter__ for an object.

    Won't the objects of a class defining __next__() method, be iterators by themselves?

    Not necessarily, as your first class defining __next__ but not __iter__ shows. __next__ is needed if you need to support iteration since it produces the values. __iter__ is needed since that's what's called on an object in the for statement in order for it to get an iterator.

    You could have a class that only defines __next__ and somewhat works (it is limited) but, it needs to be returned from someones __iter__ . For example, the class MyClass returns a class CustomIter that only defines __next__:

    class MyClass:
        def __iter__(self): 
            return CustomIter()
    
    class CustomIter(object):
    
        def __init__(self): 
            self.state = 0
    
        def __next__(self): 
            self.state += 1
            if self.state > 4:
                raise StopIteration
            return self.state
    

    You'll need an __iter__ defined on an object that will return another object (could be itself) on which __next__ is defined.


    If your class defines __iter__ as:

    def __iter__(self): return self
    

    then you need to define __next__ on type(self) (the class) since you return the instance itself. __next__ is going to get called on self until no more values can be produced.

    The other case is when __iter__ simply returns another object which defines __next__ (as per my first example). You can alternatively do that by making __iter__ a generator.

    For example:

    class MyClass:
        def __init__(self):
            self.state = 0
    
        def __iter__(self): 
            for i in range(10): yield i
    

    doesn't define a __next__. When iter is called on it though:

    g = iter(MyClass())
    

    it returns a generator g that defines __next__:

    g = iter(MyClass())
    
    g.__next__() # 0
    g.__next__() # 1
    

提交回复
热议问题