Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does iter() do to list?

I have this code:

a = ['animal', 'dog', 'car', 'bmw', 'color', 'blue']
a_iter = iter(a)

print(a)
print(a_iter)

print(dict(zip(a,a)))
print(dict(zip(a_iter,a_iter)))

and output is:

['animal', 'dog', 'car', 'bmw', 'color', 'blue']
<list_iterator object at 0x7f2d98b756d8>
{'dog': 'dog', 'car': 'car', 'animal': 'animal', 'color': 'color', 'blue': 'blue', 'bmw': 'bmw'}
{'car': 'bmw', 'color': 'blue', 'animal': 'dog'}

I do not understad, why the zip works differently with a_iter than a. What does iter() do, list is iterable, so why use iter()? Could anybody explain me this with some nice example? I googled about it but I still do not understand it.

like image 200
dorinand Avatar asked May 02 '18 10:05

dorinand


People also ask

What does ITER () do in Python?

python iter() method returns the iterator object, it is used to convert an iterable to the iterator. Parameters : obj : Object which has to be converted to iterable ( usually an iterator ). sentinel : value used to represent end of sequence.

What does ITER and next do in Python?

Iterator in Python is an object that is used to iterate over iterable objects like lists, tuples, dicts, and sets. The iterator object is initialized using the iter() method. It uses the next() method for iteration. __next__(): The next method returns the next value for the iterable.

What should __ ITER __ return?

__iter__ returns the iterator object itself and the __next__ method returns the next value from the iterator. If there is no more items to return then it raises a StopIteration exception.

Is a list An iterator?

A list is an iterable. But it is not an iterator. If we run the __iter__() method on our list, it will return an iterator. An iterator is an object with a state that remembers where it is during iteration.


1 Answers

iter() does nothing to a list; the list object has an __iter__ method that iter() uses to produce an iterator object. That object has a reference to the original list and an index; every time you ask for the next value in the iterator, the value at the current index is retrieved and returned, and the index is incremented.

You can use the next() function to get the next value from an iterator:

>>> a = ['animal', 'dog', 'car', 'bmw', 'color', 'blue']
>>> a_iter = iter(a)
>>> next(a_iter)  # get the next value
'animal'
>>> next(a_iter)  # get the next value
'dog'

Notice how calling next() again gives you a new value. You can do so until the iterator is done:

>>> three_more = next(a_iter), next(a_iter), next(a_iter)
>>> next(a_iter)  # last one
'blue'
>>> next(a_iter)  # nothing left
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

List iterator objects keep hold of the original list object; changing the list object will reflect in the iterator values produced on next():

>>> b = ['foo', 'bar']
>>> b_iter = iter(b)
>>> next(b_iter)
'foo'
>>> b[1] = 'spam'
>>> b
['foo', 'spam']
>>> next(b_iter)
'spam'

zip() asks for the next value in each of its arguments, which are assumed to be iterables; zip() calls iter() on them all. For iterator objects such as a_iter, iter(a_iter) returns the iterator itself (it's already an iterator, after all):

>>> iter(a_iter)
<list_iterator object at 0x10e7b6a20>
>>> iter(a_iter) is a_iter
True

Since a_iter will yield values from the original list, in order, that means that you get paired-up elements in a dictionary, because zip() has two references to the same object; you effectively creating (next(a_iter), next(a_iter)) as the iterator step values for zip(). If you pass in two references to a, on the other hand, zip() will call iter() twice, creating two separate iterator objects, and each have their own index to track.

Let's look at that in detail. Note that zip() also produces an iterator object, so we can verify that calling next() on zip() in turn causes a_iter to step forward twice:

>>> a_iter = iter(a)
>>> a_iter_zip = zip(a_iter, a_iter)
>>> a_iter_zip   # a zip object is an iterator too
<zip object at 0x10e7ba8c8>
>>> next(a_iter_zip)  # get next value of a_iter, together with the next value of a_iter
('animal', 'dog')
>>> next(a_iter)  # the a-list iterator was advanced, so now we get 'car'
'car'
>>> next(a_iter_zip)  # now a_iter is at bmw, so we get bmw and color
('bmw', 'color')

Iterators are independent objects, they each have their own index:

>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a)   # different iterator from a_iter1
>>> next(a_iter1), next(a_iter1)  # what zip() does
('animal', 'dog')
>>> next(a_iter2), next(a_iter2)  # iter2 is independent
('animal', 'dog')

So when you use zip(a, a), what really happens is that zip() calls iter(a) two times, creating two new iterators, and both are used to create the output:

>>> a_iter1 = iter(a)
>>> a_iter2 = iter(a)
>>> a_iter_1_and_2_zip = zip(a_iter1, a_iter2)
>>> next(a_iter_1_and_2_zip)  # values from a_iter1 and a_iter2
('animal', 'animal')
>>> next(a_iter_1_and_2_zip)  # moving in lockstep
('dog', 'dog')
>>> next(a_iter1)   # moving one of these two one step along, to 'car'
'car'
>>> next(a_iter_1_and_2_zip)   # so a_iter1 is one step ahead!
('bmw', 'car')
>>> next(a_iter1)   # another extra step
'color'
>>> next(a_iter_1_and_2_zip)   # so a_iter1 is two steps ahead!
('blue', 'bmw')
like image 146
Martijn Pieters Avatar answered Oct 06 '22 00:10

Martijn Pieters