子类重写get_obj后,父类方法如何调用自身的get_obj?
问题:子类调用方法时,强制父类方法使用自身实现
类结构代码
from abc import ABC, abstractmethod class grandparent(ABC): @abstractmethod def get_obj(self): pass class ParentBase(grandparent): def __init__(self, obj1): self.obj1 = obj1 def get_obj(self,func): return getattr(self.obj1, func) def get_base_obj(self): return super().get_obj('base') class child1(ParentBase): def __init__(self, obj1): super().__init__(obj1) def get_obj(self): return super().get_base_obj().getChild1() class child2(ParentBase): def __init__(self, obj1): super().__init__(obj1) def get_obj(self): return super().get_base_obj().getChild2()
测试代码
child_instance = child1(obj1) child_instance.get_obj()
错误情况
运行测试代码会抛出**“传入2个参数但预期1个”**的错误:
- 原因:
ParentBase.get_base_obj中调用super().get_obj('base')时,实际调用的是祖父类grandparent的抽象方法(该方法定义无参数),而非ParentBase自身的get_obj方法。 - 若修改
get_base_obj为以下形式,会调用子类重写的get_obj(无参数),同样报错:def get_base_obj(self, func_name): return self.get_obj(func)
需求
希望子类调用get_obj时,父类ParentBase的get_base_obj方法能调用父类自身的get_obj实现,而非子类或祖父类的版本。ParentBase是基类,不会被实例化,询问是否必须改为类方法或有无更优雅的实现。
临时解决方案(用户自实现)
修改ParentBase为以下形式可运行,但不够优雅:
class ParentBase(grandparent): def __init__(self, obj1): self.obj1 = obj1 def get_obj(self,func): return self.obj1 def get_base_obj(self): return ParentBase.get_obj(self, 'base')
优雅实现方案
无需改为类方法,直接通过父类名调用实例方法的方式,显式指定调用ParentBase自身的get_obj,逻辑清晰且符合Python规范:
from abc import ABC, abstractmethod class grandparent(ABC): @abstractmethod def get_obj(self): pass class ParentBase(grandparent): def __init__(self, obj1): self.obj1 = obj1 def get_obj(self, func): return getattr(self.obj1, func) def get_base_obj(self): # 显式调用父类自身的get_obj,绕过子类重写和祖父类抽象方法 return ParentBase.get_obj(self, 'base') class child1(ParentBase): def get_obj(self): return super().get_base_obj().getChild1() class child2(ParentBase): def get_obj(self): return super().get_base_obj().getChild2()
原理说明
在Python中,实例方法的第一个参数self是调用方法的实例对象。用ParentBase.get_obj(self, 'base')调用时,直接触发父类的方法实现,并将当前实例传入self,完全绕过子类的方法重写逻辑,也不会调用祖父类的抽象方法。
额外规范建议
祖父类grandparent的抽象方法get_obj无参数,但ParentBase的get_obj定义了参数,违反了抽象方法的契约(子类重写方法的签名应与抽象方法一致)。可调整祖父类定义,让参数更明确:
class grandparent(ABC): @abstractmethod def get_obj(self, func=None): pass
这样所有子类和父类的get_obj方法签名都符合抽象方法要求,代码更规范。
内容的提问来源于stack exchange,提问作者Rezzy138
相关产品推荐
相关产品推荐

