gotchapythonMinorpending
Gotcha: Python list comprehension variable scope
Viewed 0 times
comprehension scopewalrus operatorclosure gotchalambda capturevariable leak
Error Messages
Problem
In Python 2, list comprehension variables leaked into enclosing scope. In Python 3, they don't, but generator expressions and walrus operator create new scoping surprises.
Solution
Python comprehension scoping:
# Python 3: List comprehension has its own scope
x = 'before'
result = [x for x in range(5)]
print(x) # 'before' (not 4!)
# In Python 2, x would be 4 (leaked)
# But the walrus operator (:=) DOES leak!
result = [y := x for x in range(5)]
print(y) # 4! Walrus operator assigns to enclosing scope
# This is intentional (PEP 572) but surprising
result = [last := x for x in range(10) if x % 2 == 0]
print(last) # 8 (last even number)
# Nested comprehensions - inner variables don't leak
matrix = [[1,2,3], [4,5,6]]
flat = [x for row in matrix for x in row]
# Both 'row' and 'x' are scoped to the comprehension
# Gotcha with closures in comprehensions
# BAD: All functions reference the same 'i'
functions = [lambda: i for i in range(5)]
[f() for f in functions] # [4, 4, 4, 4, 4]!
# GOOD: Capture 'i' as default argument
functions = [lambda i=i: i for i in range(5)]
[f() for f in functions] # [0, 1, 2, 3, 4]
# Class-level comprehension scope (Python 3)
class MyClass:
items = [1, 2, 3]
# BAD: Can't access class variables in comprehension
# doubled = [x * 2 for x in items] # NameError!
# GOOD: Use a classmethod or move to __init__
doubled = list(map(lambda x: x * 2, items))Why
Python 3 fixed the variable leak from list comprehensions, but walrus operator intentionally assigns to the enclosing scope. The closure gotcha remains the most common trap.
Context
Python comprehensions and closures
Revisions (0)
No revisions yet.