为什么"class"没有开始像"def"这样的新范围呢?

Tim*_*ten 16 python

我不完全确定这是否适用于stackoverflow,所以请纠正我,如果没有.

即说我们有内容的t.py:

class A(object):
    pass
print("A:", A)

class B(object):
    print("From B: A:", A)


class OuterClass(object):
    class AA(object):
        pass
    print("AA:", AA)

    class BB(object):
        print("From BB: AA:", AA)
Run Code Online (Sandbox Code Playgroud)

现在我们执行它: $ python3 t.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
Run Code Online (Sandbox Code Playgroud)

来自文档:

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

所以我理解行为,但不理解使范围不像其他地方那样词汇的理由.它反对"特殊情况不足以打破规则." 为什么class表现得与举例不同def

这是一个"实用性胜过纯洁"的案例吗?如果是这样,理由是什么?我最初认为它可能是python 2.x的一个人工制品,但正如你在上面看到的那样,行为也出现在python 3.3中.

Bre*_*arn 11

正如Wooble在评论中指出的那样,类块确实创建了一个新范围.问题是嵌套在该范围内的范围无法访问类块范围中的名称.这在文档中提到:

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

我现在找不到这个的来源,但在某处(我认为在StackOverflow问题上)我找到了一个合理的理由:如果类def在嵌套块中可访问,方法名称将影响全局函数,包括内置函数.这会使创建具有简短名称的方法的类变得尴尬,但这也会使用同名的内置函数.例如,你不能这样做:

class SomeDataStructure(object):
    def sum(self):
        return sum(self._data)
    def otherCalc(self):
        return sum(item for item in somethingElse)
Run Code Online (Sandbox Code Playgroud)

如果类块在方法范围内,则会导致无限递归,因为内部sum调用可以访问方法名称并调用该方法而不是内置sum函数.同样,其他方法(例如otherCalc方法)将不再能够访问全局求和函数以供自己使用,但总是会获得该方法. 对另一个SO问题的回答通过说"这是因为你应该self用来访问Python中的方法"来描述这个问题.

现在,这样的说法实在才有感官功能的内部类,因为当函数体不被执行def的,但类主体当执行class语句.但是,我想如果你把我上面所说的内容与这篇博文中的概念结合起来,你会得到一个合理的理由.也就是说,嵌套类不是 - 并且仍然不是 - 被认为是一种值得支持的风格.但是,类中的函数当然是常见的.处理函数内部用例的最简单方法是使class块不将其名称传递给任何嵌套作用域.如果它将其名称传递给嵌套类而不是嵌套函数可能会更好,但这将是一个更复杂的规则,没有人关心支持嵌套类来使其值得.