How does [string for i, string in enumerate(a)] work in python?

185 views Asked by At

Thanks for helping me! My question been answered in the comments, by @juanpa.arrivillaga . Key point of my question is about how python know "I am trying to assign the first element to i and the second element to string".


I am learning python, but how does [string for i, string in enumerate(a)] work really troubles me.

Here are 2 example code I write while learning python

a = ['a','b','c', 'd']
d = [string for string in enumerate(a)]
print (d)

it would return '[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]'. However, if I write the following code

a = ['a','b','c', 'd']

c = [string for i, string in enumerate(a)]
print(c)

it would return ['a', 'b', 'c', 'd']

In my understanding, string in enumerate(a) would translated to the "enumerated object" like position inside RAM. and I do not tell python what the i is (I did not tell python i is the index or string is the element). So, the code would be explained as "list["enumerated object" iterate inside "i"]", but since I did not tell python what i is, it will run into error. However, it returned a list of elements from enumerate.

Where do python learned from my code the string means element inside enumerate, and i means the index?

3

There are 3 answers

0
juanpa.arrivillaga On BEST ANSWER

So, two things you need to understand. First, what is enumerate and second, how iterable unpacking works.

enumerate takes an iterable as it's first argument and a start keyword argument (that defaults to 0 if not passed explicitly). It returns an iterator of pairs, i.e. of tuples of length 2, where the first element are ints starting at start and increasing by one, and the second element comes from the original iterable you passed to enumerate.

>>> iterable = ["foo", "bar", "baz"]
>>> iterator = enumerate(iterable, start=1)
>>> next(iterator)
(1, 'foo')
>>> next(iterator)
(2, 'bar')
>>> list(iterator)
[(3, 'baz')]

Now, you need to understand iterable unpacking in assignment targets. Note, in the for clause of a for-loop or list comprehension (or dict/set comprehensions or generator expressions), you are assigning to a target. So:

>>> for x in range(4):
...     print(x)
...
0
1
2
3
>>> print("see, x is just a regular variable", x)
see, x is just a regular variable 3

Because, at the beginning of each iteration, you get the next value from the iterator created by the iterable in the in clause. Anything that goes in:

for <assignment target> in iterable

Can also go:

<assignment target> = whatever

But assignment targets can be more than a simple, single variable. The simplest extension, unpack into exactly two variables:

>>> x = 3
>>> x, y = "XY"
>>> x
'X'
>>> y
'Y'
>>> x, y = range(2)
>>> x
0
>>> y
1
>>> x, y = ['foo', 'bar']
>>> x
'foo'
>>> y
'bar'

It can get more elaborate than that but I think you already understand that.

So for i, string in whatever is you telling Python:

I expect every element in whatever (itself an iterable) to be some iterable with exactly two elements. On each iteration, assign the first item to i and the second to string. This is simply based on position, the names don't matter. They could be for banana, apple in whatever and it works the exact same way.

3
Psytho On

enumerate(a) gives you (0, 'a'), (1, 'b') and so on. In your 1st code your string is (0, 'a') and that is what you get.

In your 2nd code i is the 1st element of (0, 'a') (iterating numbers - 0, 1 etc.) and string is the 2nd element (that is elements of the original list). You take only string in your list, so you get only 2nd elements, which are element of the original list, which results in the original list.


(I did not tell python i is the index or string is the element)

You did actually. Try following and note the difference:

c = [(i, string) for i, string in enumerate(a)]
print(c)
c = [(string, i) for i, string in enumerate(a)]
print(c)
1
KRG On

Because enumerate(a) returns iterator of tuples of format (index, value_of_index)

1st case: 'string for string in enumerate(a)', the tuple (index, value_of_index) is stored in the variable 'string' which you save in the list 'd' giving you the tuples as output.

2nd case: 'string for i, string in enumerate(a)', the index is stored in variable 'i' and value_of_index in 'string' and you save the 'string' in the list 'c' giving you only the values in list 'a'.