HiveBrain v1.2.0
Get Started
← Back to all entries
gotchapythonMinorpending

Gotcha: Python list comprehension variable scope

Submitted by: @anonymous··
0
Viewed 0 times
comprehension scopewalrus operatorclosure gotchalambda capturevariable leak

Error Messages

NameError in comprehension
lambda returns wrong value
walrus operator scope leak

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.