I am currently converting a script from Python 2 to Python 3. While debugging it, I stumbled upon a part of the code that behaves differently between both versions. However, I am unable to explain this difference.
Here is a reproducer:
variable_1 = "x"
variable_2 = "y"
list_of_variables = ['variable_1', 'variable_2']
existing_variables = vars()
print([variable for variable in list_of_variables if variable in vars()])
print([variable for variable in list_of_variables if variable in existing_variables])
Python 2.7.18 shows the following output:
['variable_1', 'variable_2']
['variable_1', 'variable_2']
Whereas Python 3.9.0 displays:
[]
['variable_1', 'variable_2']
Why is the first list comprehension not working in Python 3? And why is it working when storing the content of vars()
within a variable?
CodePudding user response:
It's working in both: it's just working differently.
In Python 3, list comprehensions create their own local scope to avoid leaking variable names into the calling scope. The call to vars()
inside the list comprehension is just returning the variables defined in the list comprehension's own scope, not the scope where the list comprehension is used.
From https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries:
However, aside from the iterable expression in the leftmost for clause, the comprehension is executed in a separate implicitly nested scope. This ensures that names assigned to in the target list don’t “leak” into the enclosing scope.
CodePudding user response:
In python 3, vars() acts like locals(), which means your locals() is different inside the list comprehension. https://docs.python.org/3/library/functions.html#vars