Why a for loop?

Q: What does [i for i] do in this script? [i for i] to me is a ‘null’ statement.

my_list = [1, 2, 3, 2, 4, 2, 5]
indices = [i for i, x in enumerate(my_list) if x == my_list[0]]
print(indices)

That’s because it’s not the full expression. It’s what’s called a “list comprehension”, a way to concisely express building a new list by transforming an existing one. The line is equivalent to the following:

indices = []
for i, x in enumerate(my_list):
    if x == my_list[0]:
        indices.append(i)

The first i at the start is the value you’re wanting to add to the finished list. i, x is an implicit tuple unpacking, retrieving the two values enumerate() produces.

1 Like

Got it.

i = (i,x)

I’m not sure what you mean here. A list comprehension looks like this:

 [
   expression
   for variable(s)
   in something-iterable
   if condition
 ]

The “if condition” is optional, but you can use it to select just some
of the values from something-iterable.

The example comprehension went:

 [ i for i, x in enumerate(.......) ]

enumerate yields 2-tuples of the form (index, value) for each value
in the ....... part. These are unpacked into the variables i and
x. The expression in the example is just i, which means that the
resulting list would be the index parts of the 2-tuples.

I don’t know if this makes things more clear or not.

1 Like

It doesn’t, because the script does not have [i for i] in it. It has [i for i, x in enumerate(my_list) if x == my_list[0]] in it. The matching ] is all the way at the end, and that is important.

This entire thing is called a list comprehension and you can read about them in detail from the tutorial that is built into the official documentation - right here:

1 Like

Thanks,

Here’s my code:

my_list = [1, 2, 3, 2, 4, 2, 5]
indices = [i for i, x in enumerate(my_list) if x == my_list[1] and x in my_list if x == my_list[1]]
print(indices)

It’s a bit confusing when written like so because there is an implicit tuple there. Python treats the expression as [i for (i, x) in enumerate(my_list) if my_list[0] == x].

So its NOT a list with these 2 members:

  1. i for i
  2. x in enumerate(my_list) if my_list[0] == x

Instead, it is equivalent to:

result = []
for iteration in enumerate(my_list):
    (i, x) = iteration
    if x == my_list[0]:
        result.append(i)
     
1 Like

Not really an “implicit” tuple (not sure what one would even look like). Commas make tuples. Not parentheses. And there’s an explicit comma there.

There’s an exception: the empty tuple is ().

1 Like

Another edge-case [1] is in generator expressions like the list comprehension here: [i, i for i in range(5)] doesn’t give you tuples.


  1. although it’s more about order of operations, I suppose ↩︎

Yes, I considered mentioning that, but didn’t want to distract with it. I also wouldn’t feel wrong saying “Humans have two legs”. You likely also wouldn’t use () in that context, unless you want to iterate over an iterable of empty iterables and you want to check that they’re all empty.

That said, hmm, it’s actually not even a tuple at all. It’s a “target list”. Doc.

1 Like

@jamestwebber That gives a SyntaxError.

1 Like

Did you intend to parenthesize that somehow? I’m not sure whether you meant (i, i) or i, (i for i...), and neither does Python. Presumably the latter, since that’s a genexp?

1 Like

True, and I more often end up making this error when I’m trying to pass a generator to a function that takes an iterable (and I get a different SyntaxError then). I was just being overly pedantic [1] about the “commas define a tuple” statement.

The interpreter actually assumes the former, and suggests I parenthesize my “comprehension target”.


  1. and even worse, technically imprecise! ↩︎

(While we’re on the topic: I feel like there could be clearer terminology than “comprehension target” in that error message.)