python - 在装饰 class 多方法时丢失了自我
python - lost self while decorating class multimethods
我正在尝试根据这篇文章 http://www.artima.com/weblogs/viewpost.jsp?thread=101605 实现一种多方法方法。这种方法有两个不同之处:
- 我只需要看multimethod的第一个参数,所以不需要形成arg的元组classes
- 多方法将存在于 classes 中,它们将不是常规函数。
但是我有点混淆了我的 classes,并且在调度对 class 方法的调用时,对 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))
因此,当我在 Sender
class 上调用 send_messages
方法时,我收到 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
变量?
正如 Python 方法签名(如 def send_message(self, message, *args, **kwargs)
所建议的那样,方法的第一个参数必须是 self
对象。通常,通过执行 obj.send_message
,您可以访问 对象的 方法,而不是 classes'。尝试以下操作:
>>> class Foo():
... def bar(self):
... pass
>>> Foo.bar
<function __main__.Foo.bar>
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f5fd927cc18>>
绑定方法表示已经指定了self
。
您的 @use_for_type
装饰器在 class 级别工作,所以在您的 send_message
函数上工作,而不是绑定方法。
现在它只是找出您的代码在哪里缺少显式传递 self
,这是 __call__
中的一件事 - self
是 SendMessageMultiMethod
对象,不是 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>
我正在尝试根据这篇文章 http://www.artima.com/weblogs/viewpost.jsp?thread=101605 实现一种多方法方法。这种方法有两个不同之处:
- 我只需要看multimethod的第一个参数,所以不需要形成arg的元组classes
- 多方法将存在于 classes 中,它们将不是常规函数。
但是我有点混淆了我的 classes,并且在调度对 class 方法的调用时,对 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))
因此,当我在 Sender
class 上调用 send_messages
方法时,我收到 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
变量?
正如 Python 方法签名(如 def send_message(self, message, *args, **kwargs)
所建议的那样,方法的第一个参数必须是 self
对象。通常,通过执行 obj.send_message
,您可以访问 对象的 方法,而不是 classes'。尝试以下操作:
>>> class Foo():
... def bar(self):
... pass
>>> Foo.bar
<function __main__.Foo.bar>
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f5fd927cc18>>
绑定方法表示已经指定了self
。
您的 @use_for_type
装饰器在 class 级别工作,所以在您的 send_message
函数上工作,而不是绑定方法。
现在它只是找出您的代码在哪里缺少显式传递 self
,这是 __call__
中的一件事 - self
是 SendMessageMultiMethod
对象,不是 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>