Reputation:
I don't understand exactly why the __iter__
special method just returns the object it's called on (if it's called on an iterator). Is it essentially just a flag indicating that the object is an iterator?
EDIT: Actually, I discovered that "This is required to allow both containers and iterators to be used with the for
and in
statements." https://docs.python.org/3/library/stdtypes.html#iterator.iter
Alright, here's how I understand it: When writing a for
loop, you're allowed to specify either an iterable or an iterator to loop over. But Python ultimately needs an iterator for the loop, so it calls the __iter__
method on whatever it's given. If it's been given an iterable, the __iter__
method will produce an iterator, and if it's been given an iterator, the __iter__
method will likewise produce an iterator (the original object given).
Upvotes: 7
Views: 2275
Reputation: 1209
In Python
when ever you try to use loops
, or try to iterate over any object like below..
Lets try to understand for list
object..
>>> l = [1, 2, 3] # Defined list l
If we iterate over the above list..
>>> for i in l:
... print i
...
1
2
3
When you try to do this iteration
over list l
, Python for
loop checks for l.__iter__()
which intern return an iterator object.
>>> for i in l.__iter__():
... print i
...
1
2
3
To understand this more, lets customize the list
and create anew list class..
>>> class ListOverride(list):
... def __iter__(self):
... raise TypeError('Not iterable')
...
Here I've created ListOverride
class which intern inherited
from list
and overrided list.__iter__
method to raise TypeError
.
>>> ll = ListOverride([1, 2, 3])
>>> ll
[1, 2, 3]
And i've created anew list using ListOverride
class, and since it's list object it should iterate in the same way as list
does.
>>> for i in ll:
... print i
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __iter__
TypeError: Not iterable
If we try to iterate
over ListOverride
object ll
, we'll endup getting NotIterable
exception..
Upvotes: 0
Reputation: 387507
When you loop over something using for x in something
, then the loop actually calls iter(something)
first, so it has something to work with. In general, the for loop is approximately equivalent to something like this:
something_iterator = iter(something)
while True:
try:
x = next(something_iterator)
# loop body
except StopIteration:
break
So as you already figured out yourself, in order to be able to loop over an iterator, i.e. when something
is already an iterator, iterators should always return themselves when calling iter()
on them. So this basically makes sure that iterators are also iterable.
Upvotes: 6
Reputation: 2177
This depends what object you call iter on. If an object is already an iterator, then there is no operation required to convert it to an iterator, because it already is one. But if the object is not an iterator, but is iterable, then an iterator is constructed from the object.
A good example of this is the list object:
>>> x = [1, 2, 3]
>>> iter(x) == x
False
>>> iter(x)
<list_iterator object at 0x7fccadc5feb8>
>>> x
[1, 2, 3]
Lists are iterable, but they are not themselves iterators. The result of list.__iter__
is not the original list.
Upvotes: 3