What is this Python magic?

If you do this {k:v for k,v in zip(*[iter(x)]*2)}

, where x

is a list of anything, you end up with a dictionary with all the odd elements as keys and even those that are their values. in!

>>> x = [1, "cat", "hat", 35,2.5, True]
>>> d = {k:v for k,v in zip(*[iter(x)]*2)}
>>> d
{1: "cat", "hat": 35, 2.5: True}

      

I have a general idea of ​​how dictionary tools work, how it works zip

, how it *

extracts arguments, how it [iter(x)]*2

concatenates two copies of a list, and so I was expecting a one-to-one match eg {1: 1, "cat": "cat" ...}

.

What's going on here?

+3


source to share


2 answers


This is an interesting little piece of code! The main thing that you cannot expect is that the objects are essentially passed by reference (they are actually traversed by reference , but hey). iter()

creates an object, so "copying" it (using multiplication in the list in this case) doesn't create a new one, but rather adds another reference to the same one . This means that you have a list where l[0]

is an iterator and l[1]

is the same iterator - accessing them as the same object.

Each time the next element of the iterator is accessed, it continues with the last time it stops. Since the elements are accessed alternately between the first and second elements of the tuples being created zip()

, one iterative state advances through both elements in the tuple.



After that, the dictionary comprehension simply consumes those tuples as they expand to k, v

- just like any other dictionary comprehension.

+6


source


This one iter(x)

creates an iterator over the iterable (list or similar) x

. This iterator is copied with [iter(x)]*2

. You now have a list of two times the same iterator. This means that if I ask one of them for the value, the other (the same) will increase as well.

zip()

now gets two iterators (same) as two parameters via syntax zip(* ... )

. This means that it creates a list of pairs of the two arguments it received. It will ask for the first iterator for a value (and get x[0]

), then it will ask for another iterator for a value (and get x[1]

), then it will form a pair of two values ​​and put them in its output. Then it will do this several times until the iterators are exhausted. Thus it forms a pair x[2]

, and x[3]

then couple x[4]

and x[5]

etc.

This list of pairs is then passed to the dictionary comprehension, which pairs into the dictionary key / values.



The following might be easier to read:

{ k: v for (k, v) in zip(x[::2], x[1::2]) }

      

But that might not be as effective.

+5


source







All Articles