Reputation: 3522
I read a book about advanced topics in python. The author was trying to explain the generator.
This was his example to explain:
class rev:
def __init__(self,data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
def main():
reve = rev('zix')
for i in reve:
print(i)
if __name__=='__main__':
main()
The main idea of this code is to reverse generators. The output is :
x
i
z
The thing I found hard to understand is this part:
def __iter__(self):
return self
Can someone explain it to me?
Upvotes: 1
Views: 1386
Reputation: 69298
The iterator
protocol is comprised of two methods:
__iter__
, and__next__
Also, a requirement is that __iter__
returns self
-- so if you have an obj
that is an iterator
then
obj is iter(obj) is obj.__iter__()
is true.
This is a good thing because it allows us to say iter = iter(obj)
and if obj
was already an iterator we still have the same object.
Upvotes: 1
Reputation: 3415
When you do for x in xs
, xs
has to be an iterable, which means you can get an iterator out of it by iter(xs)
, which you can do when xs.__iter__()
is implemented. An iterator is required to implement __next__()
, so that the in
operator can consume it one by one by calling next()
on it.
Now, in your case
reve = rev("hello") # is an iterable, as there is rev.__iter__()
rev1 = iter(reve) # is an iterator, this is what rev.__iter__() returns
rev2 = next(rev1) # now go on calling next() till you get StopIteration
Type the above snippet in REPL. Run it a few times. You will get a feel for it.
Upvotes: 2
Reputation: 4399
Since your class provides an implementation for next()
it returns self
so the caller will call that when looping over your object. In contrast, if you only wanted to wrap a data structure that already provides an implementation of __iter__
and next
(e.g. list), you could return self.data.__iter__()
from your class. In that case the caller would call next()
defined on that object when doing a loop or list comprehension let's say.
class rev:
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def next(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
class rev2:
def __init__(self, data):
self.data = data
def __iter__(self):
return self.data.__iter__()
def main():
for i in rev('zix'): # str doesn't provide implementation for __iter__
print(i)
for i in rev2(['z', 'i', 'x']): # list does so no need to implement next
print(i)
Upvotes: 0