Python 'for'循环

我问的不是Python的作用域规则;我一般理解如何范围适用于Python循环。我的问题是为什么设计决策是这样做出的。例如(不是双关语):

for foo in xrange(10):
bar = 2
print(foo, bar)

上面将输出(9,2)。

这让我觉得很奇怪:'foo'实际上只是控制循环,'bar'是在循环中定义的。我可以理解为什么在循环之外访问'bar'可能是必要的(否则,for循环的功能将非常有限)。我不明白的是,为什么在循环退出后,控制变量必须保持在作用域内。根据我的经验,它只会使全局名称空间变得混乱,并使跟踪其他语言的解释器可能捕捉到的错误变得更加困难。

131059 次浏览

当使用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。

Python没有块,就像其他一些语言(如C/ c++或Java)一样。因此,Python中的作用域单元是一个函数。

最可能的答案是,它只是保持语法简单,并没有成为采用的绊脚石,而且许多人都很高兴在循环构造中为名称赋值时不必消除名称所属的作用域的歧义。变量不是在作用域中声明的,而是由赋值语句的位置暗示的。global关键字的存在就是因为这个原因(表示赋值是在全局范围内完成的)。

更新

下面是关于这个主题的一个很好的讨论:http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

先前的for循环建议 循环的局部变量具有 偶然发现存在的问题 依赖于循环变量的代码 控件退出后保持其值 循环,似乎这是

简而言之,您可以将其归咎于Python社区:P

对Python的主要影响之一是美国广播公司,这是一种荷兰开发的语言,用于向初学者教授编程概念。Python的创建者Guido van Rossum在20世纪80年代曾在ABC工作过几年。我对ABC几乎一无所知,但由于它是为初学者设计的,所以我想它的作用域一定是有限的,就像早期的BASICs一样。

对于初学者来说,如果变量是循环的局部变量,那么这些循环对于大多数实际编程来说是无用的。

在当前情况下:

# 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不是同一个变量。这不是最优的或预期的行为。

如果您在循环中有一个break语句(并且希望稍后使用迭代值,可能用于恢复、索引某些东西或给出状态),那么它将为您节省一行代码和一次赋值,因此非常方便。

这是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

我可能错了,但如果我确定不需要在循环之外访问foo,我会这样写

for _foo in xrange(10):
bar = 2