user4694244
user4694244

Reputation:

What is the purpose of __iter__ returning the iterator object itself?

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

Answers (3)

gsb-eng
gsb-eng

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

poke
poke

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

zstewart
zstewart

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

Related Questions