Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python list comprehension with dummy names identical to iterator name: ill-advised?

Say I make a list comprehension that looks something like this:

i = range(5)
a = [f(i) for i in i]

for some function f. Will using a dummy name identical to the iterator ever yield unexpected results? Sometimes I have variable names that are individual letters, and to me it is more readable to stick with the same letter rather than assigning a new one, like [f(x) for x in x] instead of [f(i) for i in x] (for instance, if the letter of the iterator x is meaningful, I will wonder what the heck i is).

like image 919
Luke Davis Avatar asked May 01 '17 20:05

Luke Davis


2 Answers

TL;DR: It is safe, technically, but it's a poor choice stylistically.

In a list comprehension, before binding the free variable of the for-loop to any object, Python will use a GET_ITER opcode on the iterable to get an iterator. This is done just once at the beginning of the loop.

Therefore in the body of the "loop" of the list comprehension (which actually creates a scope in Python 3), you may rebind the name which originally pointed to the iterable without any consequence. The iteration deals with a reference to the iterator directly, and whether or not it has a name in scope is irrelevant. The same should hold true in Python 2, though the scoping implementation details are different: the name of the collection will be lost after the comprehension, as the loop variable name will remain bound to the final element of iteration.

There is no advantage to writing the code in this way, and it is less readable than just avoiding the name collision. So, you should prefer to name the collection so that it more obvious that it is a collection:

[f(x) for x in xs]
like image 124
wim Avatar answered Sep 16 '22 14:09

wim


While you can get away with using duplicate variable names due to the way Python executes list comprehensions - even nested list comprehensions - don't do this. It may seem more readable in your opinion, but for most people, it would be very confusing.

This leads to a much more important point, however. Why use a name like i, j, or x at all? Using single letter variable names cause confusion and are ambiguous. Instead, use a variable name which clearly conveys your intent.

Or, if you don't have an need at all for the values in the iterable your iterating through(eg. You simple want to repeat a block of code a certain number of times), use a "throw-away" variable, _, to convey to the reader of your code that the value is not important and should be ignored.

But don't use non-descriptive, duplicate, single letter variable names. That will only serve to confuse future readers of your code, make your intent unclear, and create code hard to maintain and debug.

Because in the end, would you rather maintain code like this

[str(x) for x in x]

or this?

[str(user_id) for user_id in user_ids]
like image 39
Christian Dean Avatar answered Sep 17 '22 14:09

Christian Dean