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?
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 int
s 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.