在Python中确定'for'循环

时间:2010-08-31 17:52:11

标签: python scope

我不是在询问Python的范围规则;我通常理解 如何在Python for循环中使用作用域。我的问题是为什么以这种方式做出设计决策。例如(没有双关语):

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

以上将打印(9,2)。

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

7 个答案:

答案 0 :(得分:89)

最有可能的答案是,它只是保持语法简单,并不是采用的绊脚石,并且许多人都乐于在循环结构中分配名称时不必消除名称所属的范围的歧义。 。变量不在范围内声明,它由赋值语句的位置隐含。 global关键字仅因此而存在(表示分配是在全局范围内完成的)。

<强>更新

以下是关于该主题的良好讨论:http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

  

以前提出的for-loop建议   循环的局部变量   偶然发现了存在的问题   依赖于循环变量的代码   退出后保持其价值   循环,似乎这是   被认为是一个理想的特征。

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

答案 1 :(得分:52)

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

答案 2 :(得分:34)

一个非常有用的案例是使用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。

答案 3 :(得分:2)

如果循环中有一个break语句(并且以后想使用迭代值,也许可以取回,索引某些内容或提供状态),它将为您节省一行代码和一次赋值,因此有一个方便。

答案 4 :(得分:1)

Python的主要影响之一是ABC,这是荷兰开发的一种语言,用于向初学者教授编程概念。 Python的创建者Guido van Rossum在20世纪80年代在ABC工作了几年。我对ABC几乎一无所知,但是因为它适用于初学者,我认为它必须具有有限数量的范围,就像早期的BASIC一样。

答案 5 :(得分:0)

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

目前情况:

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

答案 6 :(得分:0)

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