能否在子类中调用父类__getattribute__生成的自动方法?
解决子类调用父类动态生成方法的问题
你的核心问题是:父类Upgrader通过__getattribute__动态生成upgrade_vN方法,但子类Foo自己实现了同名方法后,无法在子类方法里调用父类动态生成的版本。之前尝试的几种方式失效的原因如下:
Upgrader.upgrade_v2(self):父类类本身没有定义upgrade_v2,动态生成逻辑是在实例的__getattribute__里,直接通过类调用找不到方法。super().upgrade_v2():super()会去父类的类属性里查找方法,而父类类里没有upgrade_v2,自然找不到。Upgrader.__getattribute__(self, "upgrade_v2"):这个调用会优先找实例所属类(也就是Foo)里的upgrade_v2,拿到的是子类自己的方法,不是父类动态生成的版本。
下面给出几种可行的解决方案:
方案1:改用__getattr__替代__getattribute__
__getattr__只有在实例找不到对应属性时才会触发,而__getattribute__是每次属性访问都会触发。修改父类后,可以直接调用父类的__getattr__来获取动态方法:
class Upgrader: max = 99 def _upgrade_no_op(self, db): if self.version < Upgrader.max: self.version += 1 # 把__getattribute__换成__getattr__ def __getattr__(self, key): if key.startswith("upgrade_v"): nr = int(key[9:]) if 0 <= nr < self.max: return self._upgrade_no_op raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{key}'") class Foo(Upgrader): version = 1 def upgrade_v2(self, db): # 直接调用父类的__getattr__获取动态生成的方法 parent_upgrade = Upgrader.__getattr__(self, "upgrade_v2") parent_upgrade(db) # 这里添加子类自己的升级逻辑 print("执行Foo自定义的v2升级逻辑") Foo().upgrade_v2("dummy_db")
方案2:在父类中添加辅助方法
如果不想修改__getattribute__的逻辑,可以在Upgrader里加一个专门获取父类动态升级方法的函数,避免子类自己处理属性查找的细节:
class Upgrader: max = 99 def _upgrade_no_op(self, db): if self.version < Upgrader.max: self.version += 1 def __getattribute__(self, key): try: return super().__getattribute__(key) except AttributeError: if key.startswith("upgrade_v"): nr = int(key[9:]) if 0 <= nr < self.max: return self._upgrade_no_op raise # 新增辅助方法,直接返回指定版本的默认升级方法 def get_default_upgrade(self, version): key = f"upgrade_v{version}" # 跳过子类的方法,直接触发父类的动态生成逻辑 try: # 先尝试从父类类属性找,找不到则走动态逻辑 return super().__getattribute__(key) except AttributeError: if 0 <= version < self.max: return self._upgrade_no_op raise AttributeError(f"无效的升级版本:{version}") class Foo(Upgrader): version = 1 def upgrade_v2(self, db): # 调用辅助方法获取父类默认升级逻辑 self.get_default_upgrade(2)(db) # 子类自定义逻辑 print("执行Foo自定义的v2升级逻辑") Foo().upgrade_v2("dummy_db")
方案3:直接调用父类的默认实现(不推荐)
如果确定父类动态生成的方法始终是_upgrade_no_op,可以直接在子类里调用这个方法,但这种方式硬编码了父类的内部实现,后续父类逻辑变更时需要同步修改子类:
class Foo(Upgrader): version = 1 def upgrade_v2(self, db): # 直接调用父类的_no_op方法 Upgrader._upgrade_no_op(self, db) # 子类自定义逻辑 print("执行Foo自定义的v2升级逻辑")
内容的提问来源于stack exchange,提问作者Matthias Urlichs
相关产品推荐
相关产品推荐

