Python作用域和类/实例/继承命名空间



给定

class A:
x = 'Ac'
def f(self):
return self.x
class B(A):
x = 'Bc'
def f(self):
return self.x
class C(A):
x = 'Cc'
def f(self):
return self.x
class D(B, C):
x = 'Dc'
def __init__(self):
self.x = 'Di'
def f(self):
return self.x
d = D()
  1. d.x的名称解析顺序是什么?例如Di, Dc, Bc, Cc, Ac

  2. super(D, d).x的名称解析顺序是什么?

  3. super(D, d).f()self.x的nro是多少?它与d.f()相同吗?

  4. D.x的nro是多少?

  5. 如果我分配给d.x,而Di不在那里,它会去哪里?例如DiDc

  6. 如果我分配给D.x,而Dc不在那里,它会去哪里?

  7. 如果我分配给super(D, d).x,而Bc不在那里,它会去哪里?例如DiDcBc

如果您的对象是新样式对象(继承自object),您可以使用__mro__属性或mro方法打印出方法解析顺序来获得答案。

将A类修改为如下所示:

class A(object):
...

然后你可以打印出每个类的方法分辨率顺序:

>>> A.__mro__
(<class 'junk.A'>, <type 'object'>)
>>> B.__mro__
(<class 'junk.B'>, <class 'junk.A'>, <type 'object'>)
>>> C.__mro__
(<class 'junk.C'>, <class 'junk.A'>, <type 'object'>)
>>> D.__mro__
(<class 'junk.D'>, <class 'junk.B'>, <class 'junk.C'>, <class 'junk.A'>, <type 'object'>)

新样式Python类中的stackoverflow问题方法解析顺序(MRO)提供了一些有用的信息。

首先,如果在每个点分配不同的值,而不是在所有地方都分配None,这会让事情变得容易得多。但我会尽力按要求回答你的问题。

首先要注意的是,d实例实际上只有x的1个副本,而不是4个。你可以很容易地测试这个:

>>> d.x = 3
>>> B.f(d)
3

在像C++这样的语言中,输出应该是None,因为D有单独的B::x、C::x和D::x数据成员。(我在这里假装A不存在,因为它使讨论变得更加复杂,而且实际上与问题无关。)

或者,更容易:

>>> dir(d)
['__doc__', '__init__', '__module__', 'f', 'x']

这就是所有的成员;你已经给同一个自己分配了四次。

另一方面,每个类都有自己的副本。如果没有实例变量,则按与mro相同的顺序搜索这些变量。你可以再次轻松测试:

>>> del d.x
>>> B.x = 4
>>> C.x = 5
>>> D.x = 6
>>> d.f()
6
>>> C.f(d)
6
>>> del D.x
>>> d.f()
4

至于设置,这很容易:设置d.x总是设置实例变量(记住,只有1个,而不是4个),或者在不存在实例变量的情况下创建实例变量。同时,设置D.xB.x为该类设置或创建类变量。因此,继承层次结构是无关紧要的。

最新更新