Python生成器表达式与自定义生成器执行差异及变量绑定疑问
Let's walk through your questions step by step—these examples highlight some tricky but crucial behavior in Python's generator implementation.
First Question: Why does the generator expression use old a for iteration but new a for condition checks?
In the first example:
a = [1, 2, 3] b = (c for c in a if c in a) a = [2, 3, 4] print(list(b)) # Output: [2, 3]
Here's the breakdown:
- Generator expressions have a special variable binding rule: The iterable in the
forclause (ainfor c in a) is evaluated immediately when the generator is created. So whenbis defined, Python grabs a reference to the original[1,2,3]list and stores it for later iteration. - The condition check (
if c in a) is lazy-evaluated—it doesn't resolve the variableauntil the generator actually runs (when you calllist(b)). By that time,ahas been reassigned to[2,3,4], so each element from the original list is checked against this new list.
That's why we end up with elements 2 and 3: they're from the original list, and they exist in the new list.
Second Question: Why do custom generators behave differently?
Your custom generator function:
def d(expr): for c in expr: if c in expr: yield c a1 = [1,2,3] t = d(a1) a1 = [2,3,4] print(list(t)) # Output: [1, 2, 3]
The key difference here is parameter passing:
- When you call
d(a1), Python evaluatesa1immediately and passes a reference to the original[1,2,3]list into the function as theexprparameter. - Inside the generator, both
for c in exprandif c in exprrefer to this fixedexprparameter (the original list), not the externala1variable. Reassigninga1later has no effect on theexprvariable inside the generator.
So when you iterate over t, you're looping through the original list and checking membership against the same original list—all elements pass the check, hence the output [1,2,3].
Bonus: What happens when we replace a with literal lists?
In this modified example:
a = [1, 2, 3] b = (c for c in [1,2,3] if c in [2, 3, 4]) a = [2, 3, 4] print(list(b)) # Output: [2,3]
Both [1,2,3] and [2,3,4] are literal lists, so they're evaluated immediately when the generator is created. They're independent of the a variable entirely—reassigning a later doesn't touch these lists. The generator iterates over [1,2,3] and checks against [2,3,4], which gives us the same result as the first example, but without the variable reassignment confusion.
内容的提问来源于stack exchange,提问作者rtut

