【发布时间】:2020-10-04 09:23:27
【问题描述】:
在Effective Python一书中,作者建议使用赋值表达式来避免理解中的冗余,例如:
def fun(i):
return 2 * i
result = {x: y for x in [0, 1, 2, 3] if (y := fun(x)) > 3}
而不是
result = {x: fun(x) for x in [0, 1, 2, 3] if fun(x) > 3}
result 的值为 {2: 4, 3: 6}。
作者说
如果一个推导在推导的值部分使用海象运算符并且没有条件,它会将循环变量泄漏到包含范围中。 [...] 最好不要泄漏循环变量,因此我建议仅在推导式的条件部分使用赋值表达式。
但是,在上面的示例中,y 在程序结束时设置为 6。所以,赋值表达式中的变量泄露了,虽然它是在条件中定义的。
列表推导也会发生同样的事情:
>>> _ = [(x, leak) for x in range(4) if (leak := 2 * x) > 3]
>>> leak
6
甚至对于生成器表达式:
>>> it = ((x, leak) for x in range(4) if (leak := 2 * x) > 3)
>>> next(it)
(2, 4)
>>> leak
4
>>> next(it)
(3, 6)
>>> leak
6
我错过了什么?有什么办法可以完全避免在理解中的赋值表达式泄漏?
【问题讨论】:
-
Python 没有变量的块作用域,唯一的作用域是函数和类定义。所以文中的解释对我来说真的没有意义。
-
生成器和列表推导也没有建立新的范围。
-
这是旧的,但有一些关于 python 3.X 的更新:stackoverflow.com/questions/4198906/…
-
@Barmar 事实上他们这样做了:
x = 1; print([locals() for y in range(1)])打印y并且不从外部范围打印x。 -
@kaya3 你是对的。更重要的是:
[y for y in range(1)]不会将y泄漏到包含范围内。直到您发表评论,我才意识到这一点
标签: python python-assignment-expression