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).
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]
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With