我试图用新方法装饰类实例。但是如果装饰者从它自己的方法中添加了一个方法,它会给我一个错误
TypeError: myMethod() takes 1 positional argument but 2 were given
举一个最小的例子,假设我有一个MyElement类我无法修改,而且Decorator将一个方法从它自己添加到MyElement的实例
class MyElement(object):
def __init(self):
self._name = "MyElement"
class Decorator(object):
def myMethod(self):
print(self._name)
def decorate(self, element):
element.myMethod = MethodType(self.myMethod, element)
if __name__ == '__main__':
d = Decorator()
p = MyElement()
d.decorate(p)
p.myMethod()
这给了我上面的错误。 Altough如果我改变装饰,它可以工作:
def decorate(self, element):
element.myMethod = MethodType(self.myMethod.__func__, element)
有人可以解释一下MethodType究竟在做什么吗?为什么 func 标志是必要的?
答案 0 :(得分:2)
您正在使用MethodType
将Decorator
myMethod
方法绑定到另一个对象。这不起作用,因为当您使用self.myMethod
访问它时,您已经获得了绑定方法。第一个绑定将Decorator
对象作为self
传递,第二个绑定在尝试将MyElement
实例作为第二个参数传递时导致异常。
有几种方法可以解决这个问题。目前尚不清楚哪一个最适合您,因为myMethod
示例并未对self
执行任何操作。
一种选择是通过myMethod
课程访问Decorator
,而不是通过self
。这意味着它将被解除绑定(直到您将其包装在MethodType
中)。在此版本中,self
中显示的myMethod
值将是MyElement
实例,而不是Decorator
(这对于阅读代码的人来说可能会令人惊讶)。在Python 2中,未绑定的方法进行了特殊检查self
是正确的类型,因此这不起作用。
def decorate(self, element):
element.myMethod = MethodType(Decorator.myMethod, element)
另一种选择是将self.myMethod
的绑定方法保存为element
上的变量而不尝试再绑定它。使用这种方法,self
仍将是装饰器对象,即使该方法是通过MyElement
对象调用的。
def decorate(self, element):
element.myMethod = self.myMethod
最后一个选项是保留decorate
方法,但为myMethod
添加一个额外的参数。这将允许传递Decorator
实例(作为self
)和MyElement
实例:
def myMethod(self, element):
print("{} is decorated by {}".format(element, self))