即使在理解范围之后,列表理解也会重新绑定名称。这是对的吗?
推导式显示出与范围界定的不寻常交互。这是预期的行为吗?
x = "original value"
squares = [x**2 for x in range(5)]
print(x) # Prints 4 in Python 2!
冒着抱怨的风险,这是一个残酷的错误来源。当我编写新代码时,我偶尔会发现由于重新绑定而导致的非常奇怪的错误 - 即使现在我知道这是一个问题。我需要制定一条规则,例如“始终在列表推导式中使用下划线作为临时变量的前缀”,但即使这样也不是万无一失的。 事实上,这种随机定时炸弹等待的事实否定了列表理解的所有良好的“易用性”。
Comprehensions show unusual interactions with scoping. Is this the expected behavior?
x = "original value"
squares = [x**2 for x in range(5)]
print(x) # Prints 4 in Python 2!
At the risk of whining, this is a brutal source of errors. As I write new code, I just occasionally find very weird errors due to rebinding -- even now that I know it's a problem. I need to make a rule like "always preface temp vars in list comprehensions with underscore", but even that's not foolproof.
The fact that there's this random time-bomb waiting kind of negates all the nice "ease of use" of list comprehensions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
列表推导式会在 Python 2 中泄漏循环控制变量,但在 Python 3 中不会泄漏。这是 Guido van Rossum(Python 的创建者)解释这背后的历史:
List comprehensions leak the loop control variable in Python 2 but not in Python 3. Here's Guido van Rossum (creator of Python) explaining the history behind this:
是的,列表推导式在 Python 2.x 中“泄漏”了它们的变量,就像 for 循环一样。
回想起来,这被认为是一个错误,并且通过生成器表达式避免了它。编辑:作为 马特B. 注意到当集合和字典理解语法从 Python 3 向后移植时,也可以避免这种情况。
列表理解的行为必须保留在 Python 2 中,但它在 Python 3 中已完全修复。
这意味着在all of:
x 始终是表达式的本地变量,而这些:
在 Python 2.x 中 all 将
x
变量泄漏到周围范围。Python 3.8 更新:PEP 572< /a> 引入了
:=
赋值运算符,它故意泄漏出推导式和生成器表达式!这种泄漏本质上是由 2 个用例引发的:从any()
和all()
等早期终止函数捕获“见证”:以及更新可变状态:
请参阅< a href="https://www.python.org/dev/peps/pep-0572/#appendix-b-rough-code-translations-for-compressivens" rel="nofollow noreferrer">附录 B以获得准确的范围。该变量会在最接近的周围
def
或lambda
中分配,除非该函数将其声明为nonlocal
或global
。Yes, list comprehensions "leak" their variable in Python 2.x, just like for loops.
In retrospect, this was recognized to be a mistake, and it was avoided with generator expressions. EDIT: As Matt B. notes it was also avoided when set and dictionary comprehension syntaxes were backported from Python 3.
List comprehensions' behavior had to be left as it is in Python 2, but it's fully fixed in Python 3.
This means that in all of:
the
x
is always local to the expression while these:in Python 2.x all leak the
x
variable to the surrounding scope.UPDATE for Python 3.8: PEP 572 introduced
:=
assignment operator that deliberately leaks out of comprehensions and generator expressions! This leaking was motivated by essentially 2 use cases: capturing a "witness" from early-terminating functions likeany()
andall()
:and updating mutable state:
See Appendix B for exact scoping. The variable is assigned in closest surrounding
def
orlambda
, unless that function declares itnonlocal
orglobal
.是的,赋值发生在那里,就像在 for 循环中一样。没有创建新的范围。
这绝对是预期的行为:在每个周期中,该值都绑定到您指定的名称。例如,
一旦认识到这一点,似乎很容易避免:不要在推导式中使用现有的变量名称。
Yes, assignment occurs there, just like it would in a
for
loop. No new scope is being created.This is definitely the expected behavior: on each cycle, the value is bound to the name you specify. For instance,
Once that's recognized, it seems easy enough to avoid: don't use existing names for the variables within comprehensions.
有趣的是,这不会影响字典或集合推导式。
然而,如上所述,它已在 3 中修复。
Interestingly this doesn't affect dictionary or set comprehensions.
However it has been fixed in 3 as noted above.
对于 python 2.6,当这种行为不合需要时,可以使用一些解决方法
some workaround, for python 2.6, when this behaviour is not desirable
在 python3 中,在列表理解中,变量在作用域结束后不会发生变化,但是当我们使用简单的 for 循环时,变量会被重新分配到作用域之外。
我 = 1
打印(一)
print([i 在范围 (5) 内])
打印(一)
i 的值将仅保持为 1。
现在只需使用 for 循环,i 的值就会被重新分配。
In python3 while in list comprehension the variable is not getting change after it's scope over but when we use simple for-loop the variable is getting reassigned out of scope.
i = 1
print(i)
print([i in range(5)])
print(i)
Value of i will remain 1 only.
Now just use simply for loop the value of i will be reassigned.