Python 为什么';";“类”;开始一个新的范围,如;def";做

Python 为什么';";“类”;开始一个新的范围,如;def";做,python,Python,我不完全确定这是stackoverflow,所以如果不是,请纠正我 i、 e.假设我们有带内容的t.py: 现在我们执行它:$python3t.py A: <class '__main__.A'> From B: A: <class '__main__.A'> AA: <class '__main__.AA'> From BB: AA: Traceback (most recent call last): File "t.py", line 9, in

我不完全确定这是stackoverflow,所以如果不是,请纠正我

i、 e.假设我们有带内容的t.py:

现在我们执行它:
$python3t.py

A: <class '__main__.A'>
From B: A: <class '__main__.A'>
AA: <class '__main__.AA'>
From BB: AA:
Traceback (most recent call last):
  File "t.py", line 9, in <module>
    class OuterClass(object):
  File "t.py", line 14, in OuterClass
    class BB(object):
  File "t.py", line 15, in BB
    print "From BB: AA:", AA
NameError: name 'AA' is not defined
A:
B:A:
AA:
来自BB:AA:
回溯(最近一次呼叫最后一次):
文件“t.py”,第9行,在
类OuterClass(对象):
文件“t.py”,第14行,在外层
BB类(对象):
文件“t.py”,第15行,BB中
打印“来自BB:AA:”,AA
名称错误:未定义名称“AA”
从文档中:

类定义是一个可执行语句。它首先评估 继承列表(如果存在)。继承列表中的每个项都应 计算为允许子类化的类对象或类类型。这个 然后在新的执行框架中执行类的套件(参见第节) 命名和绑定),使用新创建的本地命名空间和 原始全局命名空间。(通常,套件只包含功能 定义。)当类的套件完成执行时 框架被丢弃,但其本地名称空间被保存。[4] 班级 然后使用基类的继承列表创建对象 以及为属性字典保存的本地名称空间。班级 名称绑定到原始本地命名空间中的此类对象

因此,我理解这种行为,但不理解使范围不像其他地方那样是词汇化的背后的原理。这与“特殊情况不足以违反规则”背道而驰。为什么
class
的行为与
def
不同


这是一个“实用性胜过纯洁性”的案例吗?如果是,理由是什么?我最初认为它可能是Python2.x的产物,但正如您在上面所看到的,这种行为也出现在Python3.3中。

正如Wooble在评论中所指出的,类块确实创建了一个新的范围。问题是类块作用域中的名称不能被嵌套在该作用域中的作用域访问。这在以下章节中提到:

类块中定义的名称范围仅限于类块;它不扩展到方法的代码块——这包括理解和生成器表达式,因为它们是使用函数作用域实现的

我现在找不到这个问题的根源,但在某个地方(我想是关于StackOverflow的问题),我找到了一个合理的理由:如果类def可以在嵌套块中访问,那么方法名将隐藏全局函数,包括内置函数。这将使创建具有短而简单名称的方法的类变得很尴尬,但同时也使用相同名称的内置函数。例如,您不能这样做:

class SomeDataStructure(object):
    def sum(self):
        return sum(self._data)
    def otherCalc(self):
        return sum(item for item in somethingElse)
如果类块在方法的作用域内,这将导致无限递归,因为内部
sum
调用将访问方法名称,并将调用该方法而不是内置的
sum
函数。类似地,其他方法(如
otherCalc
方法)将不再有权访问全局求和函数以供自己使用,而是始终使用该方法。描述这一点时说“这是因为您应该使用
self
来访问Python中的方法”


现在,这个参数只对类内的函数有意义,因为函数体在
def
为时不执行,而类体在
class
语句为时执行。然而,我认为如果你把我上面所说的和来自的概念结合起来,你会得到一个合理的理由。也就是说,嵌套类没有——现在仍然没有——被认为是一种值得支持的样式。当然,类中的函数是很常见的。处理function-inside-a-class用例的最简单方法是使
块不将其名称传递给任何嵌套的作用域。如果它将其名称传递给嵌套类而不是嵌套函数,可以说会更好,但这将是一个更复杂的规则,没有人关心支持嵌套类是否值得。

可能重复@Wooble,我不这么认为。这个问题解释了这种行为(就像文档一样),但并没有解释其背后的理性。也许会有帮助。在任何情况下,您的标题都具有误导性;你的问题是内部类定义确实创建了一个新的作用域,而不是没有。@aaron digulla你为什么要重命名这个问题?我最初问“在python类定义中,什么是不以词汇形式定义类主体的rational?”这与“为什么“类”不能像“def”那样开始一个新的作用域?”有很大不同,后来改为“rational”。rational是正确的词,而不是“rational”,仅供参考。
class SomeDataStructure(object):
    def sum(self):
        return sum(self._data)
    def otherCalc(self):
        return sum(item for item in somethingElse)