装饰方法(类方法重载)
问题内容:
受Muhammad
Alkarouri答案的启发,在Python3的“函数注释”中有什么用处,我想multimethod
对方法而不是常规函数进行此操作。但是,当我这样做时
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
。
但是我不知道如何使它工作。好吧,当我删除“自我”时,它(几乎)可以正常工作,但我不想删除它。请注意,我这样做是为了练习,我知道有一些库可以提供方法重载。
我试过的
-
很无聊的,但想尝试-添加的参数
self
在def multimethod( function )
同一个错误- -
我想到了在增加
__init__
的class MultiMethod
第三个参数-obj
并存储self
为成员,但我无法通过做到这一点multimethod
,因为它是一个函数。 -
我不想为装饰器添加参数,因此将忽略此选项(如果可能的话)
我读了几个类似的问题,但没有找到我想要的东西。我很确定这是一个假问题,但是我没有想法。
问题答案:
您的基本问题是使用类代替函数。没有将该类绑定到调用它的实例的机制,这与自动执行该函数的函数不同。
简而言之,当您执行a.foo( .. )
此操作时,它会返回MultiMethod
,但该对象并不知道应该绑定到a
。
您必须以某种方式传递实例。一种简单的方法是将所有内容包装在一个函数中,然后让Python完成操作:
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
执行此绑定的类上编写自己的描述符。