我不完全确定这是针对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中。
答案 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
块不将其名称传递给任何嵌套作用域。如果它将其名称传递给嵌套类而不是嵌套函数可能会更好,但这将是一个更复杂的规则,没有人关心支持嵌套类来使其值得。