我正在尝试编写一个为 python 提供方法重载功能的装饰器,类似于 PEP 3124 中提到的那个.
我编写的装饰器非常适合常规函数,但我无法让它用于类中的方法。
这是装饰器:
class Overload(object):
def __init__(self, default):
self.default_function = default
self.type_map = {}
self.pos = None
def __call__(self, *args, **kwargs):
print self
try:
if self.pos is None:
pos = kwargs.get("pos", 0)
else:
pos = self.pos
print args, kwargs
return self.type_map[type(args[pos])](*args, **kwargs)
except KeyError:
return self.default_function(*args, **kwargs)
except IndexError:
return self.default_function(*args, **kwargs)
def overload(self, *d_type):
def wrapper(f):
for dt in d_type:
self.type_map[dt] = f
return self
return wrapper
当我尝试这样实现它时:
class MyClass(object):
def __init__(self):
self.some_instance_var = 1
@Overload
def print_first_item(self, x):
return x[0], self.some_instance_var
@print_first_item.overload(str)
def print_first_item(self, x):
return x.split()[0], self.some_instance_var
我在运行时遇到了一个TypeError
:
>>> m = MyClass()
>>> m.print_first_item(1)
<__main__.Overload object at 0x2> (1,) {}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "overload.py", line 17, in __call__
return self.default_function(*args, **kwargs)
TypeError: print_first_item() takes exactly 2 arguments (1 given)
>>>
我的问题是:如何从装饰方法中访问 MyClass
的实例(即 self
)?
最佳答案
本质上,您的Overload
类需要一个__get__
方法:
def __get__(self, obj, cls):
# Called on access of MyClass.print_first_item.
# We return a wrapper which calls our
print "get", self, obj, cls
if obj is None:
# a function would do some checks here, but we leave that.
return self
else:
return lambda *a, **k: self(obj, *a, **k)
为什么?
好吧,您将Overload
对象用作一种函数替换。您希望它像函数一样在具有不同签名的方法上下文中表示自己。
简要说明方法访问的工作原理:
object.meth(1, 2)
被翻译成
object.__dict__['meth'].__get__(object, type(object))(1, 2)
函数的 __get__()
返回一个方法对象,该对象通过将对象添加到参数列表(结果为 self
)包装函数:
realmethod = object.__dict__['meth'].__get__(object, type(object))
realmethod(1, 2)
其中 realmethod
是一个方法对象,它知道要调用的函数和要给它的 self
并通过转换调用适本地调用“真实”函数进入
meth(object, 1, 2)
.
我们在这个新的 __get__
方法中模仿了这种行为。
关于python - 方法重载装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11371309/