Reputation: 327
Can someone explain to me how the __iter__()
and __next__()
functions handle indices? Are they base 0
or base 1
?
I have been playing around with it, but I'd like to know what Python is actually doing on the back end. I tried the example class below:
>>> class my_class:
def __init__(self, *stuff):
self.__stuff = stuff
def __iter__(self):
self.__n = 0
return iter(self.__stuff)
def __next__(self):
if self.__n <= len(self.__stuff):
self.__n += 1
return self.__stuff(self.__n)
else:
raise StopIteration
>>> x = my_class(1, 2, 3, 4)
>>> for each in x:
print(each)
1
2
3
4
Unless, I'm mistaken, the first self.__n
value that __next__()
uses should be 1
, which should produce, this:
>>> for each in x:
print(each)
2
3
4
What am I missing? How does it know to start at self.__stuff[0]
?
Upvotes: 0
Views: 961
Reputation: 21
my_class
, it first calls the __init__
, then calls the __iter__
, last is the __next__
. __iter__
, it return iter(self.__stuff)
,then is over, __next__
is not called. So the output is what you see.If you want __next__
called, you can change your code like this(here self.__n that __next__
uses starts from 1):
class my_class:
def __init__(self, *stuff):
self.__stuff = stuff
def __iter__(self):
self.__n = 0
print('__iter__ is called')
return self
def __next__(self):
print('__next__ is called')
if self.__n <= len(self.__stuff):
self.__n += 1
return self.__stuff(self.__n)
else:
raise StopIteration
Tip: you can use print
to help you understand what the code is doing, like print
function in the code above.
Upvotes: 2
Reputation: 1518
When you call for each in x:
, it do nothing with __next__()
in your class definition, so it start 1 of your object attribute rather than 2.
Even it you want to call something like print(next(x))
it will give you 'TypeError: 'tuple' object is not callable', because self.__stuff(self.__n)
is invalid as in self.__stuff
is a tuple and self.__n
is an integer. You can only call tuple[int]
rather than tuple(int)
.
Try following code after your code mentioned it will return you desired output then raise an exception.
for each in x:
print(next(x))
Result:
2
3
4
raise StopIteration
Upvotes: 3
Reputation: 798676
The __iter__()
method returns iter(self.__stuff)
instead of self
. As such, the tuple passed to __init__()
is iterated over, not the object.
Upvotes: 1