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

时间:2012-12-18 16:46:45

标签: 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)

现在我们执行它:$ 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

来自文档:

  

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

所以我理解行为,但不理解使范围不像其他地方那样词汇的理由。它反对“特殊情况不足以打破规则。”为什么class的行为与def

的行为不同

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

1 个答案:

答案 0 :(得分:11)

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

  

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

我现在找不到这个的来源,但在某个地方(我想在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方法之类的其他方法将不再能够访问全局求和函数以供自己使用,但总是会获得该方法。 An answer to another SO question通过说“这是因为您应该使用self来访问Python中的方法”来描述这一点。

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