Python 3中父类何时及如何被实例化?代码验证常见误解
哎,你发现的这个点其实是Python继承里一个非常容易踩的坑!咱们先来看看你提供的代码和输出:
class AClass: def __init__(self): print("make A") self.val = True def f(self): return self.val class BClass(AClass): def __init__(self): print("make B") self.val = False def g(self): return self.val b = BClass() print(b.f()) print(b.g())
输出结果:
make B False False
问题原因
你之所以看不到父类的make A输出,核心原因是子类重写了__init__方法,但没有显式调用父类的__init__。在Python中,当子类定义了自己的构造函数时,Python不会自动帮你调用父类的构造逻辑——它默认认为你已经在子类的__init__里处理了所有初始化需求,包括父类的部分。
所以实例化BClass时,只会执行子类的__init__:打印make B,并把self.val设为False。而父类的__init__完全没被触发,自然不会打印make A,也不会设置父类里的self.val=True。
至于b.f()返回False,是因为虽然f()是父类的方法,但它访问的是当前实例b的val属性——这个属性已经被子类的__init__设置成False了,所以不管调用父类还是子类的方法,拿到的都是这个值。
解决办法
如果想让父类的初始化逻辑也执行,你需要在子类的__init__里显式调用父类的__init__方法,有两种常用方式:
方式1:使用super()(推荐)
super()是Python 3里推荐的写法,它能自动帮你找到父类,不需要硬编码父类名称:
class BClass(AClass): def __init__(self): super().__init__() # 先调用父类的构造函数 print("make B") self.val = False
方式2:直接调用父类的__init__
也可以直接指定父类名称来调用,不过这种写法在多重继承时容易出问题,一般不推荐:
class BClass(AClass): def __init__(self): AClass.__init__(self) # 直接调用父类构造,必须传self参数 print("make B") self.val = False
修改后再运行代码,输出就会变成:
make A make B False False
如果不想让子类覆盖父类的val,可以去掉子类里的self.val = False,这时候b.f()和b.g()都会返回True,因为父类的__init__已经把val设为True了。
总结一下
Python继承中,子类重写__init__后,父类的构造函数不会自动执行,必须手动显式调用。这和一些其他语言(比如Java)的自动链式调用不一样,所以刚开始用Python继承的时候很容易忽略这一点~
内容的提问来源于stack exchange,提问作者M Wade

