Python“ for”循环的作用域


177

我不是在问Python的作用域规则。我大致了解作用域在Python中用于循环的原理。我的问题是为什么设计决策是以这种方式做出的。例如(无双关语):

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

上面将打印(9,2)。

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


6
如果您不希望for循环使全局名称空间混乱,请将其包装在函数中。关闭嘉豪!
詹森(Jathanism)2010年

24
除非您在全局名称空间中运行循环(不常见),否则它将使本地名称空间混乱。
格伦·梅纳德

2
如果这不存在,那么您如何在以后在循环中停下来的点继续处理?只需在循环之前定义控制变量?
endolith

8
@endolith是的...为什么不要求?
史蒂文·卢

3
人们只会喜欢他们过去所做的事情。我会说这种事情伤害了习惯于这种事情的python编码器,并且在切换到另一种语言时必须经历痛苦的​​过程。对于我们其他人,我认为这是一个简洁的小捷径。
史蒂文·卢

Answers:


107

最可能的答案是,它只是使语法简单,没有成为采用的绊脚石,而且许多人都对在循环结构中分配名称时不必消除名称的范围感到满意。变量不在范围内声明,而是由赋值语句的位置隐含。该global关键字存在只是为了这个原因(象征分配在全球范围内完成)。

更新资料

这里是关于该主题的精彩讨论:http : //mail.python.org/pipermail/python-ideas/2008-October/002109.html

以前的使for循环变量位于循环本地的建议,偶然发现了现有代码的问题,该代码依赖循环变量在退出循环后保持其值,这似乎被认为是理想的功能。

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


2
如果归纳变量的范围限于循环的主体,语法将如何变得更加复杂?这种变化将仅限于Python中的语义分析,而不是其语法。
2015年

6
循环不是Python中的块。这种行为上的改变要求从根本上改变语法或提供特殊情况。归纳变量的整个概念在当前语法中也未表达。语法为口译员的口译提供了约定。我的观点是,我无法预见到如何在不使语法更加复杂的情况下改变这种行为。由于设计决策的副作用已成为一个特征,因此一切都没有意义。
杰里米·布朗

1
这篇文章mail.python.org/pipermail/python-dev/2005-September/056677.html提供了有关布朗先生所暗示的速度和复杂性的更多详细信息。
rajesh

61

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


3
我很困惑-是什么导致Python无法像作用域那样对作用域进行作用域限定?
chimeracoder 2010年

35
并不是真的,只是语法没有疯狂。(docs.python.org/reference/…)“块是作为单元执行的一段Python程序文本。以下是块:模块,函数体和类定义...”
杰里米布朗2010年

1
@thebackhand,什么都没有。只是认为没有必要。
哈比人2010年

@杰里米·布朗-的确如此。好的
atzz 2010年

6
@thebackhand-在具有块的语言中,作用域for循环是一般原则的自然扩展。在Python中,这必须是特例,除非特有优势,否则应避免使用特例。
atzz 2010年

39

一个非常有用的案例是使用时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
您大概可以在else子句中完成该操作,即。else: print "I did something {0} times".format(count)-在本地范围(Python中不存在)消失之前
Nas Banov

3
只有第二个示例在Python 3中不起作用,对吧?第一个还是吗?关于为何将其从Python 3中删除的说明?
endolith

7
对于计数,枚举(a,start = 1)中的项目: #默认索引从零开始
Tao Zhang

3
第一个示例不是一个好用例,它看起来更像是该范围界定规则很危险并且不应该依赖的证据。如果someiterator是空的怎么办?
最大

1
@Nas虽然else在这种情况下可以使用子句,但是由于循环体可能会break过早,因此它通常不会起作用。
jamesdlin

2

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


1

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


-1

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

在当前情况下:

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


5
没有回答这个问题。OP询问的是foo,而不是total(在示例中为bar)。
詹姆斯·布拉德伯里

6
@JamesBradbury total并且foo在OP的场景中仍然具有本地循环绑定,并且逻辑是相同的。
柯克·斯特拉瑟

2
OP:“我明白为什么在循环外需要访问'bar'的必要性(否则,for循环的功能非常有限)。我不明白的是为什么必须保留控制变量循环退出后的范围。” (重点是我的)
詹姆斯·布拉德伯里

2
@JamesBradbury您可能是正确的,但我三年前回答了这个问题,现在可能不值得争论。
柯克·斯特拉瑟
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.