在下面,B是从Bbase继承的外部类,而A是从Abase继承的内部类。
我用类变量B.b = None创建B,然后更改B.b。然后,我重复该过程。在新的派生类中,我发现确实B.b = None,所以我创建了B类的原始副本,这是我的意图。到目前为止,一切都很好。
同样在B中,我创建了一个具有类变量A.a = None的类A,我也对此进行了更改。
但是,在该过程的重复中,我认为我的A的新副本原来具有等于先前更改的值的A.a,而不是我从基类的初始化程序中期望的None。就是说,我毕竟还没有收到过原始的A副本,但是我的B副本包含了我之前创建的相同的A类(或者可能是具有相同更改的副本)。以下代码和输出显示了这一点。
我实际上希望B的其他原始副本包含A的原始副本,而不是A的先前修改版本。我该如何做到这一点?
代码:
class Abase():
a = None
class Bbase():
b = None
class A(Abase): pass
print('Run 1')
class B(Bbase): pass
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "None None")')
B.b = 23
B.A.a = 47
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "23 47")')
print()
print('Run 2')
class B(Bbase): pass
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "None None")')
B.b = 23
B.A.a = 47
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "23 47")')
输出(Python 3.7.0,MacOS 10.13.6):
Run 1
B.b, B.A.a= None None (Expect "None None")
B.b, B.A.a= 23 47 (Expect "23 47")
Run 2
B.b, B.A.a= None 47 (Expect "None None") <====
B.b, B.A.a= 23 47 (Expect "23 47")
顺便说一句,如果我在B之外创建A,然后通过B.A = A
将其插入B中,则将达到预期的效果。不过,我希望像在B类中的其他对象一样,在B中创建它。
首先,由于进行了这次讨论并与Hack Manhattan的同事进行了跟进,我对关于继承在Python中的工作方式的严重误解感到失望。我以为,像class Bbase(): pass; class B(Bbase): pass
这样的调用创建了一个新的类B,然后从概念上讲,从Bbase中的代码执行了B。但是实际上,从概念上讲,它只是将对象复制到在创建Bbase时创建的对象中。 。那是我的啊哈!时刻。也许其他人会发现这很有用。 (请注意,最后的解释也是错误的。请参见下面与user2357112的讨论。)
第二,以下方法效果很好:
class Abase():
a = None
class Bbase():
b = None
@classmethod
def getA(cls):
class A(Abase): pass
cls.A = A
然后,我可以重复执行class B(Bbase): pass; B.getA()
之类的调用,每次,我将得到一个包含原始A的原始B。这有点像猴子的补丁,将猴子保持在笼子里。