Why does a class need to define __iter__()
returning self, to get an iterator of the class?
class MyClass:
def __init__(self):
self.stat
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