装饰方法(类方法重载) [英] Decorating method (class methods overloading)
问题描述
受Muhammad Alkarouri的启发,其答案在 Python3的良好用法是什么? ; Function Annotations" ,我想对方法(而不是常规函数)执行此multimethod
.但是,当我这样做
Inspired by Muhammad Alkarouri answer in What are good uses for Python3's "Function Annotations" , I want to do this multimethod
for methods, not regular functions. However, when I do this
registry = {}
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
def multimethod(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
types = tuple(function.__annotations__.values())
mm.register(types, function)
return mm
class A:
@multimethod
def foo(self, a: int):
return "an int"
a = A()
print( a.foo( 1 ) )
我知道了:
Traceback (most recent call last):
File "test.py", line 33, in <module>
print( a.foo( 1 ) )
File "test.py", line 12, in __call__
return function(*args)
TypeError: foo() takes exactly 2 arguments (1 given)
由于self
,如装饰方法所述,这似乎是预期的.论点.
Which seems to be expected, as explained in Decorating a method , because of the self
argument.
但是我不知道如何使它工作.好吧,当我删除自我"时,它(几乎)可以正常工作,但是我不想删除它.请注意,我这样做是为了练习,我知道有一些库可以提供方法重载.
But I have no idea how to make it work. Well, when I remove the "self", it's working (almost) fine, but I don't want to remove it. Please note, that I'm doing this for practice, I know that there are some libs, providing method overloading.
我尝试过的事情:
-
非常愚蠢,但想尝试-在
def multimethod( function )
中添加了参数self
-相同的错误
very silly, but wanted to try - added parameter
self
indef multimethod( function )
- the same error
我考虑过要在class MultiMethod
的__init__
中添加第三个参数-obj
并将self
存储为成员,但是我无法通过multimethod
进行此操作,因为它是一个函数.
I thought about adding in the __init__
of class MultiMethod
a third parameter - obj
and stored self
as member, but I can't do this through multimethod
as it is a function.
我不想为装饰器添加参数,因此将忽略此选项(如果可能的话)
I don't want to add parameters for the decorator, so this options (if possible at all) is ignored
我读了几个类似的问题,但没有找到我想要的东西.我很确定这是一个虚拟的问题,但是我没有想法了.
I read several similar questions, but didn't find what I was looking for. I'm pretty sure this is dummy question, but I ran out of ideas.
推荐答案
您遇到的基本问题是,您使用类代替了函数.没有将该类绑定到从其调用的实例的机制,这与自动执行该功能的函数不同.
The basic problem you have is that you use a class in place of a function. There is no mechanism to bind that class to the instance it's called from, unlike a function where this happens automatically.
简而言之,当您执行a.foo( .. )
时,它会返回MultiMethod
,但是此对象不知道应该绑定到a
.
In short, when you do a.foo( .. )
it returns a MultiMethod
, but this object has no idea that it is supposed to be bound to a
.
您必须以某种方式传递实例.一种简单的方法是将所有内容包装在一个函数中,然后由Python完成:
You have to pass in the instance in some way or another. One easy way is to wrap it all in a function and let Python do it's thing:
registry = {}
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
# self = a MultiMethod instance, instance = the object we want to bind to
def __call__(self, instance, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(instance, *args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
def multimethod(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
types = tuple(function.__annotations__.values())
mm.register(types, function)
# return a function instead of a object - Python binds this automatically
def getter(instance, *args, **kwargs):
return mm(instance, *args, **kwargs)
return getter
class A:
@multimethod
def foo(self, a: int):
return "an int", a
a = A()
print( a.foo( 1 ) )
更复杂的方法是在执行此绑定的A
类上编写自己的描述符.
The more complex way would be to write your own descriptor on the A
class that does this binding.
这篇关于装饰方法(类方法重载)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!