装饰方法(类方法重载)
受到 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
参数。
但我不知道如何让它发挥作用。好吧,当我删除“自我”时,它工作(几乎)正常,但我不想删除它。请注意,我这样做是为了练习,我知道有一些库提供方法重载。
我尝试过的:
非常愚蠢,但想尝试 - 在
def multimethod( function )
中添加参数self
- 相同的错误我考虑添加
__init__
的 < code>class MultiMethod 第三个参数 -obj
并将self
存储为成员,但我无法通过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 ) )
I got this:
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)
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.
What I tried:
very silly, but wanted to try - added parameter
self
indef multimethod( function )
- the same errorI thought about adding in the
__init__
ofclass MultiMethod
a third parameter -obj
and storedself
as member, but I can't do this throughmultimethod
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您遇到的基本问题是您使用类代替函数。没有机制将该类绑定到调用它的实例,这与自动发生的函数不同。
简而言之,当您执行
a.foo( .. )
时,它会返回一个MultiMethod
,但该对象不知道它应该绑定到a
。您必须以某种方式传递实例。一种简单的方法是将其全部包装在一个函数中,然后让 Python 完成它的工作:
更复杂的方法是在执行此绑定的
A
类上编写您自己的描述符。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.
In short, when you do
a.foo( .. )
it returns aMultiMethod
, but this object has no idea that it is supposed to be bound toa
.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:
The more complex way would be to write your own descriptor on the
A
class that does this binding.