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

Python类中实现multimethod装饰器时丢失self的问题解决

解决类中多方法分发时丢失self的问题

这个问题的核心是类方法的绑定机制和你的多方法调用逻辑不匹配,导致参数传递顺序完全错位了。让我一步步给你拆解问题,再给出修复方案:

问题根源

当你用@use_for_type装饰器把Sender类里的send_message方法替换成SendMessageMultiMethod实例后,调用self.send_message(message)时,Python会自动把Sender的实例(也就是你原本期望的self)作为第一个参数传给SendMessageMultiMethod的__call__方法。但你原来的__call__方法签名是:

def __call__(self, message, extra_payload=None):

这里的第一个self是SendMessageMultiMethod自己的实例,所以实际参数传递变成了:

  • SendMessageMultiMethod实例 → __call__的self
  • Sender实例 → __call__的message
  • 你传入的message → __call__的extra_payload

然后你调用注册的方法时,又把message(实际是Sender实例)传给了类方法的第一个参数,自然就出现了self变成数值/布尔值,message为None的情况。

修复方案

我们需要调整SendMessageMultiMethod的__call__方法,让它能正确接收Sender的实例,并把它传递给注册的类方法。

修改后的完整代码

method_registry = {}
class SendMessageMultiMethod(object):
    """ A class for implementing multimethod functionality """
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, instance, message, extra_payload=None):
        """ Overrriding method call and dispatching it to an actual method based on the supplied message class """
        first_arg_type = message.__class__
        function = self.typemap.get(first_arg_type)
        print( 
            'Dispatching to function {} with message {} and extra payload {}...'
            .format(function, message, extra_payload) 
        )
        # 把Sender实例作为第一个参数传给注册的类方法
        return function(instance, message, extra_payload)
    def register(self, type_, function):
        self.typemap[type_] = function

def use_for_type(*types):
    """ A decorator that registers a method to use with certain types """
    def register(method):
        """Creating Multimethod with the method name and registering it at at method_registry dict """
        name = method.__name__
        mm = method_registry.get(name)
        if mm is None:
            mm = method_registry[name] = SendMessageMultiMethod(name)
        for type_ in types:
            mm.register(type_, method)
        return mm
    return register

class Sender(object):
    def send_messages(self, messages_list):
        for message in messages_list:
            self.send_message(message)
    @use_for_type(int, float)
    def send_message(self, message, *args, **kwargs):
        print('received call for int/float message {} with {}, {}'
              .format(message, args, kwargs))
        print('self is {}'.format(self))
    @use_for_type(bool)
    def send_message(self, message, *args, **kwargs):
        print('received call for bool message {} with {}, {}'
              .format(message, args, kwargs))
        print('self is {}'.format(self))

关键修改点

  1. 调整__call__的参数签名:
    新增instance参数,用来接收Sender类的实例(也就是原本的self),参数顺序变成(self, instance, message, extra_payload=None)。
  2. 调用注册方法时传递instance:
    在return function(instance, message, extra_payload)这一行,把instance作为第一个参数传给注册的类方法,确保类方法能拿到正确的self。

测试运行结果

现在执行你的测试代码:

sender = Sender()
sender.send_messages([1, 2, True, 5.6])

会得到正确的输出:

Dispatching to function <function Sender.send_message at 0x1013608c8> with message 1 and extra payload None...
received call for int/float message 1 with (None,), {}
self is <__main__.Sender object at 0x10135f9d0>
Dispatching to function <function Sender.send_message at 0x1013608c8> with message 2 and extra payload None...
received call for int/float message 2 with (None,), {}
self is <__main__.Sender object at 0x10135f9d0>
Dispatching to function <function Sender.send_message at 0x101360950> with message True and extra payload None...
received call for bool message True with (None,), {}
self is <__main__.Sender object at 0x10135f9d0>
Dispatching to function <function Sender.send_message at 0x1013608c8> with message 5.6 and extra payload None...
received call for int/float message 5.6 with (None,), {}
self is <__main__.Sender object at 0x10135f9d0>

可以看到self现在是正确的Sender实例,message也拿到了预期的值。

如果想去掉args里的None,可以在__call__里判断extra_payload,如果是None就不传,或者调整类方法的参数签名,这里就看你的需求啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:51:05