Python for 循环中的作用域
- 2024-12-09 08:30:00
- admin 原创
- 138
问题描述:
我并不是在问 Python 的作用域规则;我大致了解Python for 循环中的作用域是如何工作的。我的问题是为什么要以这种方式做出设计决策。例如(无意双关):
for foo in xrange(10):
bar = 2
print(foo, bar)
以上内容将打印(9,2)
。
这让我觉得很奇怪:foo
实际上只是控制循环,并且bar
是在循环内部定义的。我可以理解为什么可能需要在bar
循环外部访问 for(否则,for 循环的功能将非常有限)。我不明白的是为什么控制变量在循环退出后仍必须在范围内。根据我的经验,它只会使全局命名空间变得混乱,并使追踪其他语言的解释器可以捕获的错误变得更加困难。
解决方案 1:
最可能的答案是,它只是保持了语法的简单性,不会成为采用的绊脚石,而且许多人都很高兴在循环构造中赋值时不必消除名称所属范围的歧义。变量不是在范围内声明的,它由赋值语句的位置暗示。global
关键字的存在就是为了这个原因(表示赋值是在全局范围内完成的)。
更新
这里有一个关于该主题的很好的讨论: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html
先前提出的将 for 循环变量设为循环本地的提议遇到了现有代码的问题,即依赖于循环变量在退出循环后保持其值,而这似乎被视为一个理想的特性。
简而言之,你大概可以把责任归咎于 Python 社区 :P
解决方案 2:
Python 没有块,而其他一些语言(例如 C/C++ 或 Java)有。因此,Python 中的作用域单位是一个函数。
解决方案 3:
一个非常有用的情况是当使用时enumerate
,您希望最后得到总数:
for count, x in enumerate(someiterator, start=1):
dosomething(count, x)
print "I did something {0} times".format(count)
有必要吗?没必要。不过确实很方便。
另外要注意的是:在 Python 2 中,列表推导中的变量也会泄露:
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9
但是,这并不适用于 Python 3。
解决方案 4:
Python 的主要影响之一是ABC,这是荷兰开发的一种语言,用于向初学者传授编程概念。Python 的创建者 Guido van Rossum 在 20 世纪 80 年代花了数年时间研究 ABC。我对 ABC 几乎一无所知,但由于它是为初学者设计的,我想它的范围一定有限,就像早期的 BASIC 一样。
解决方案 5:
我可能是错的,但如果我确定我不需要foo
在循环外访问,我会这样写
for _foo in xrange(10):
bar = 2
解决方案 6:
如果循环中有一个 break 语句(并且想要稍后使用迭代值,也许是用来恢复、索引某些内容或提供状态),它会为您节省一行代码和一个分配,因此很方便。
解决方案 7:
这是 Python 中的一种设计选择,它通常使得某些任务比具有典型块范围行为的其他语言更容易。
但很多时候你还是会想念典型的块作用域,因为,比如说,你可能有大量的临时数组,需要尽快释放。这可以通过临时函数/类技巧来实现,但仍然有一个更简洁的解决方案,即直接操作解释器状态。
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://github.com/l74d/scoping
解决方案 8:
首先,如果变量是循环局部的,那么这些循环对于大多数实际编程来说都是无用的。
在当前情况下:
# Sum the values 0..9
total = 0
for foo in xrange(10):
total = total + foo
print total
产生45
。现在,考虑一下 Python 中的赋值是如何工作的。如果循环变量是严格本地的:
# Sum the values 0..9?
total = 0
for foo in xrange(10):
# Create a new integer object with value "total + foo" and bind it to a new
# loop-local variable named "total".
total = total + foo
print total
0
因为total
赋值后的循环内部变量与循环外部变量不同,所以会产生收益total
。这不是最佳或预期的行为。