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