oriaj oriaj - 1 year ago 25
Python Question

Why are these two calls different in python?

I'm just begin with python but I can understand why this to call get different result

from itertools import izip
a = ['hello','world','1','2', 'other', 'thing']
b = ['hello','world','1','2', 'other', 'thing']
i = iter(a)
i2= iter(b)
c = dict(izip(i, i2))


Result:

{'thing': 'thing', '1': '1', 'other': 'other', '2': '2', 'world': 'world', 'hello': 'hello'}





from itertools import izip
a = ['hello','world','1','2', 'other', 'thing']
i = iter(a)
c = dict(izip(i, i))


Result:

{'1': '2', 'other': 'thing', 'hello': 'world'}

Answer Source

An iterator returned by iter will yield each element from the given iterable only once. You can imagine each iterator returned by iter as if there was a sign pointing to the next element. In the first excerpt you have 2 signs: i and i2, and in the second just one. An iterator supports a single operation called next, which will get the item that the "sign" is pointing to currently, and moves the "sign" so that it points to the following element.


zip(p, q) / izip(p, q) will internally get the next element from p, then from q and build a tuple of these elements, and yield it; and then repeat for as long as p and q both have next elements.

In the first case there are 2 independent iterators. So both i and i2 will yield all the elements in their respective lists. I will present it here using simpler code and zip - as a bonus, this is Python 3 -compatible:

>>> a = [1, 2, 3, 4]
>>> p = iter(a)
>>> q = iter(a)
>>> list(zip(p, q))
[(1, 1), (2, 2), (3, 3), (4, 4)]

In the second case you passed in the same iterator twice. izip still thinks it has 2 iterators; so izip will first ask p for the next element, and then q for the next element - but there is only one iterator - so izip will see every second element coming from p, and every second from q:

>>> a = [1, 2, 3, 4]
>>> p = iter(a)
>>> q = p
>>> q is p
True
>>> list(zip(p, q))
[(1, 2), (3, 4)]

Finally, dict, when given an iterable of tuples, will construct a dictionary with first element of each tuple becoming a key, and the second element becoming the value for that key. Thus:

>>> dict([(1, 1), (2, 2), (3, 3), (4, 4)])
{1: 1, 2: 2, 3: 3, 4: 4}

and

>>> dict([(1, 2), (3, 4)])
{1: 2, 3: 4}

By the way, this code is needlessly complicated:

a = ['hello', 'world', '1', '2', 'other', 'thing']
b = ['hello', 'world', '1', '2', 'other', 'thing']
i = iter(a)
i2= iter(b)
c = dict(izip(i, i2))

First of all, the list need not be duplicated - you can have 2 iterators iterate over the same list and they would work independently, i.e. you can have

i2 = iter(a)

and still get the same result, b is needless here.

Second, most of the time you don't need to create iterators explicitly - implicit will do. Thus the code for the first case could simply be written as

a = ['hello', 'world', '1', '2', 'other', 'thing']
c = dict(zip(a, a))
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download