我正在尝试根据本文http://www.artima.com/weblogs/viewpost.jsp?thread=101605实施多方法方法。此方法有两个区别:


我只需要查看multimethod的第一个参数,因此无需形成arg类的元组
多重方法将存在于类中,而不是常规函数。


但是,我有点混淆了我的类,并且在分派对类方法的调用时,对self的调用丢失了。

这是我的代码:

method_registry = {}


class SendMessageMultiMethod(object):
    """
    A class for implementing multimethod functionality
    """
    def __init__(self, name):
        self.name = name
        self.typemap = {}

    def __call__(self, 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)
        )
        return function(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:
            # this is supposed to fire different send_message() methods
            # for different arg types
            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))


因此,当我在send_messages类上调用Sender方法时,我在self中而不是在message变量中接收参数。这里:

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


如何不丢失self并将消息内容分派到message变量?

最佳答案

正如def send_message(self, message, *args, **kwargs)这样的Python方法签名所暗示的,方法的第一个参数必须是self对象。通常,通过执行obj.send_message,可以访问对象的方法,而不是类的方法。请尝试以下操作:

>>> class Foo():
...     def bar(self):
...         pass

>>> Foo.bar
<function __main__.Foo.bar>

>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f5fd927cc18>>


bound方法表示已经指定了self

您的@use_for_type装饰器在类级别上起作用,因此在您的send_message函数而不是绑定方法上起作用。

现在,仅要弄清楚代码中明确缺少通过self的地方,这是在__call__中的一件事-selfSendMessageMultiMethod对象,而不是Sender对象-在装饰器中:

class SendMessageMultiMethod(object):
    ...

    # note the `self_` parameter
    def __call__(self, self_, message, extra_payload=None):
        ...
        return function(self_, message, extra_payload)


def use_for_type(*types):
    ...

    def register(method):
        ...

        return lambda self, *args, **kwargs: mm(self, *args, **kwargs)


输出:

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

关于python - python-装饰类多重方法时迷失自我,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48483650/

10-12 17:31
查看更多