You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用方法引用调用时,Python继承中的重写机制失效问题

解决Python继承场景下字典动态调用方法不触发重写的问题

问题重现

你通过字典实现方法动态调用,但子类重写的方法无法被正确触发,示例代码如下:

class A():
    def sum(self, id: int):
        return 1

    def multiply(self, id: int):
        return 2

    def process(self, type: str, id: int):
        callable_method = self.__dispatcher.get(type)
        return callable_method(self, id)

    __dispatcher = { "+": sum,  "*": multiply  } 

class B(A):
    def process(self, type: str, id: int):
        return super(B, self).process(type, id)

    def multiply(self, id: int):
        return 3

# 调用后返回2而非预期的3
ob = B()
print(ob.process("*", 0))

可行解决方案

方案1:通过方法名字符串动态获取实例方法

将字典存储的改为方法名而非直接的方法引用,在process中用getattr从实例获取方法,这样会遵循Python的方法解析顺序(MRO),优先调用子类重写的方法:

class A():
    def sum(self, id: int):
        return 1

    def multiply(self, id: int):
        return 2

    def process(self, type: str, id: int):
        method_name = self.__dispatcher.get(type)
        if not method_name:
            raise ValueError(f"Unsupported type: {type}")
        callable_method = getattr(self, method_name)
        return callable_method(id)

    __dispatcher = { "+": "sum",  "*": "multiply" } 

class B(A):
    def process(self, type: str, id: int):
        return super(B, self).process(type, id)

    def multiply(self, id: int):
        return 3

# 调用返回3,符合预期
ob = B()
print(ob.process("*", 0))

方案2:在实例初始化时构建绑定方法的字典

将__dispatcher改为实例属性,在__init__中绑定当前实例的方法,这样子类实例化时会自动绑定子类重写后的方法:

class A():
    def __init__(self):
        # 初始化时绑定实例的方法
        self.__dispatcher = { "+": self.sum,  "*": self.multiply } 

    def sum(self, id: int):
        return 1

    def multiply(self, id: int):
        return 2

    def process(self, type: str, id: int):
        callable_method = self.__dispatcher.get(type)
        if not callable_method:
            raise ValueError(f"Unsupported type: {type}")
        return callable_method(id)

class B(A):
    def process(self, type: str, id: int):
        return super(B, self).process(type, id)

    def multiply(self, id: int):
        return 3

# 调用返回3,符合预期
ob = B()
print(ob.process("*", 0))

问题原因分析

原代码中__dispatcher是类级别的属性,存储的是父类A的sum和multiply函数对象(未绑定方法)。当你调用callable_method(self, id)时,直接执行的是A类中定义的方法逻辑,不会触发子类的重写——因为它绕过了Python实例的方法查找链,直接调用了父类的原始函数。

而上述两种方案都通过不同方式遵循了Python的方法解析规则:方案1通过getattr从实例动态查找方法,方案2在实例初始化时绑定了已经经过MRO解析的实例方法,因此都能正确调用子类重写后的方法。

内容的提问来源于stack exchange,提问作者pxm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:33:20