python中的内部类求值顺序

python中的内部类求值顺序,python,class,inner-classes,operator-precedence,Python,Class,Inner Classes,Operator Precedence,假设我在python 3.6中这样做: class A: class B: pass class C: x = B() 在C中实例化B时,如果没有定义B,则此操作失败。 然而,这: class A: x = 1 y = x def f(self): return self z = f 很好 当然,这是: class A: pass class B: x = A() 同样有效

假设我在python 3.6中这样做:

class A:
    class B:
        pass
    class C:
        x = B()
C
中实例化
B
时,如果没有定义
B,则此操作失败。
然而,这:

class A:
    x = 1
    y = x

    def f(self):
        return self

    z = f
很好

当然,这是:

class A:
    pass

class B:
    x = A()
同样有效


为什么内部类定义不遵循与其他所有定义相同的逻辑规则?

这里的问题不是定义顺序,它与其他所有定义一样工作,而是类主体范围的特殊性质。本质上,只能使用类名称空间访问类主体范围中的变量,例如
MyClass.my\u class\u变量
。它的特殊之处在于它不创建封闭作用域,这就是为什么您无法访问
my_class\u variable
,并且被迫在方法定义中使用类名称空间的原因。阅读更多关于这方面的信息。因此,
B
实际上是被定义的。请注意,以下工作:

In [4]: class A:
   ...:     class B:
   ...:         pass
   ...:     x = B.__name__
   ...:
   ...:

In [5]: A.x
Out[5]: 'B'
现在,您可能希望以下方法能够奏效:

In [6]: class A:
   ...:     class B:
   ...:         pass
   ...:     class C:
   ...:         x = A.B()
   ...:
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-a145c80eee84> in <module>()
----> 1 class A:
      2     class B:
      3         pass
      4     class C:
      5         x = A.B()

<ipython-input-1-a145c80eee84> in A()
      2     class B:
      3         pass
----> 4     class C:
      5         x = A.B()
      6

<ipython-input-1-a145c80eee84> in C()
      3         pass
      4     class C:
----> 5         x = A.B()
      6
编辑 因此,这个例子应该很有启发性:

In [14]: x = 'global'

In [15]: class Foo:
    ...:     x = 'foooooo!'
    ...:     def bar(self):
    ...:         return x
    ...:

In [16]: Foo().bar()
Out[16]: 'global'

In [17]: Foo.x
Out[17]: 'foooooo!'

另外,这是一个相关的问题,我认为理解答案会很有启发性。谢谢。我不确定我是否理解这种行为背后的基本原理。@CharlesLanglois嗯,这是一种用动态语言实现类作用域的简单方法。基本上,您希望类的行为类似于该类实例(以及从该类继承的类型的对象)的全局命名空间,您可以在其中绑定状态和行为。它不会引起太多问题,除非您尝试在类中进行大量嵌套(这在Python中应该很少见-通常没有很好的理由),或者在类体中进行大量处理(同样,可能不是一个好主意)。您所说的“类似于全局命名空间”是什么意思?为什么类定义范围的行为不像全局范围或函数范围那么重要?我发现我不能像在全局范围中一样定义在类定义中相互引用的嵌套类,这让我感到困惑和沮丧。至于没有充分的理由,我认为这是品味的问题。我认为将相关内容打包到一个类体中而不是争论模块名称空间是很有意义的。。。古怪的
In [14]: x = 'global'

In [15]: class Foo:
    ...:     x = 'foooooo!'
    ...:     def bar(self):
    ...:         return x
    ...:

In [16]: Foo().bar()
Out[16]: 'global'

In [17]: Foo.x
Out[17]: 'foooooo!'