0

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?

Funnyone
  • 3
  • 2
  • "would translated to the "enumerated object" like position inside RAM" I don't understand what you are saying here. None of this is really directly related to RAM besides the fact that the process uses volatile memory. Python doesn't know that `string` means the string, and `i` means the index, you **told it to expect an iterable of two elements**, and you said *assign the first element to `i` and the second element to `string`. – juanpa.arrivillaga Aug 16 '23 at 08:39
  • Ignoring `enumerate` for a moment, are you familiar with how unpacking works? i.e. are you comfortable that `a = (3, 4, 5)` and `a, b, c = (3, 4, 5)` are both valid statements, with different results? – slothrop Aug 16 '23 at 08:49
  • @Juanpaarrivillaga So where do I tell python "assign the first element to i and the second element to string"? That's my confusing point. – Funnyone Aug 16 '23 at 08:51
  • @slothrop I do familiar with this concept. – Funnyone Aug 16 '23 at 08:53
  • 1
    right here: `for i, string in whatever` says "I expect ever elemnt in `whatever` (an iterable itself) to be some iterable with exactly two elements. On each iteration, assign the first item to `i` and the second to `string`. The names don't matter, you can do `for banana, apple in enumerate(a): print(banana, apple)` – juanpa.arrivillaga Aug 16 '23 at 08:54
  • 1
    Cool, so if you take `a, b, c = (3, 4, 5)` and ask the question "where do I tell Python to assign the first element to a, the second element to b, and the third element to c", that's clear, right? The order of the variables on the left hand side tells Python which element to assign to which variable. – slothrop Aug 16 '23 at 08:55
  • @juanpa.arrivillaga Thank you, this help me (and is the answer I am looking for) ! (Just a quick question What book/chapter should I look into to further study these?) Sorry for possible notification boom with @, I am still a new hand using stackoverflow to ask questions) – Funnyone Aug 16 '23 at 08:57
  • @Funnyone here is where it is described in the official docs, in the language reference for [assignment statements](https://docs.python.org/3/reference/simple_stmts.html#grammar-token-python-grammar-target_list). But note, "assignment targets" can appear in other constructs. – juanpa.arrivillaga Aug 16 '23 at 09:11

3 Answers3

1

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)
Psytho
  • 3,313
  • 2
  • 19
  • 27
  • Still have some confusions, I just read about 'for' act as list comprehensions here. So, 'for i: c.append(string)'. I still confused where did I tell python 'i' = 'index' and 'string' = 'element'? – Funnyone Aug 16 '23 at 08:49
  • @Funnyone you didn't, and python doesn't know that. *You know that*. All python knows is to expect an iterable of size two, which is precisely what `enumerate` would give you. If you gave it something else, e.g. `[for i, x in range(10)]` you would get an error. – juanpa.arrivillaga Aug 16 '23 at 08:50
  • @Funnyone you assign two elements of a tuple to ``i`` and ``string``. First element which is index is assigned to ``i``, second element iis assigned to ``string``. It doesn't matter how you name your variables! Their order is cricuial. – Psytho Aug 16 '23 at 08:58
1

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.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
0

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'.

KRG
  • 655
  • 7
  • 18