如何在子类重写的方法中使用返回实例的父类classmethod?
问题:子类调用父类classmethod时,如何让父类方法返回父类实例?
我使用Python 3.9,现有一个父类的classmethod会返回该类的实例。我希望在子类中调用父类的这个classmethod,同时返回子类的实例。示例代码如下:
class A: def __init__(self, s): print("init in class A") self.s = s @classmethod def f(cls, s): print("f in class A") return cls(s) class B(A): def __init__(self, s): print("init in class B") super().__init__(s) @classmethod def f(cls, s): print("f in class B") a = A.f(s) # a = super(B, cls).f(s) # a = super().f(s) s = "class B " + a.s return cls(s)
当使用A.f(s)时,输出结果符合预期:
>>> B.f("toto").s f in class B f in class A init in class A init in class B init in class A 'class B toto'
但如果取消子类B中classmethod f里任意一行注释(比如super(B, cls).f(s)),输出变为:
>>> B.f("toto").s f in class B f in class A init in class B init in class A init in class B init in class A 'class B toto'
结果正确,但我不理解为何父类A的classmethod会先调用B的__init__方法?我感觉此时父类classmethod中的cls仍指向子类B,不知道如何修改才能让cls指向A。
原因分析
当你用super(B, cls).f(s)或者super().f(s)调用父类的f方法时,传递给A.f的cls参数其实是子类B。因为调用B.f("toto")时,B.f内部的cls就是B,super的作用只是帮你找到父类A的f方法,但调用这个方法时,cls参数并不会被替换成A,还是保持原来的B。所以A.f里执行return cls(s)时,实际创建的是B的实例,自然会先触发B的__init__。
解决方案
如果你想让父类的f方法返回A的实例,直接用A.f(s)就可以——这就是你最初的写法,显式调用A的类方法时,A.f内部的cls就是A,创建的是A的实例,只会触发A的__init__,完全符合你的需求。
不需要用super来调用这个父类方法,因为你的目标就是获取父类的实例,直接调用父类的类方法是最直接且清晰的实现方式。
内容的提问来源于stack exchange,提问作者Ger
相关产品推荐
相关产品推荐

