关于python:为什么“class”没有像“def”那样开始新的范围呢?

Why doesn't “class” start a new scope like “def” does?

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

也就是说,我们有包含以下内容的T.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
9
10
11
12
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 class definition is an executable statement. It first evaluates the
inheritance list, if present. Each item in the inheritance list should
evaluate to a class object or class type which allows subclassing. The
class’s suite is then executed in a new execution frame (see section
Naming and binding), using a newly created local namespace and the
original global namespace. (Usually, the suite contains only function
definitions.) When the class’s suite finishes execution, its execution
frame is discarded but its local namespace is saved. [4] A class
object is then created using the inheritance list for the base classes
and the saved local namespace for the attribute dictionary. The class
name is bound to this class object in the original local namespace.

因此,我理解行为,但不理解使范围不像其他地方那样具有词法意义的理由。它违背了"特殊情况不足以打破规则",为什么class的行为与def的行为不同?

这是一个"实用胜纯洁"的例子吗?如果是这样,有什么理由?我最初认为它可能是Python 2 .x的一个伪像,但正如上面所见,Python 3.3也存在这种行为。


正如Wooble在注释中指出的,类块确实创建了一个新的范围。问题是类块作用域中的名称不能被嵌套在该作用域中的作用域访问。文件中提到了这一点:

The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods – this includes comprehensions and generator expressions since they are implemented using a function scope.

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

1
2
3
4
5
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语句是时执行的。然而,我认为如果你把我上面所说的和这篇博文的观点结合起来,你会得到一个合理的理由。也就是说,嵌套类并没有被认为是一种值得支持的样式。不过,类内的函数当然是司空见惯的。处理类内函数用例的最简单方法是使class块不将其名称传递给任何嵌套范围。可以说,如果将其名称传递给嵌套类而不是嵌套函数,会更好,但这将是一个更复杂的规则,而且没有人关心支持嵌套类以使其具有价值。