我正在尝试用新方法装饰类实例。但是如果装饰器从它自己添加一个方法,它会给我一个错误
TypeError: myMethod() takes 1 positional argument but 2 were given
举一个最简单的例子,假设我有一个我无法修改的类 MyElement,以及一个装饰器将其自身的方法添加到 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()
这给了我上面的错误。不过,如果我将装饰更改为它,它会起作用:
def decorate(self, element):
element.myMethod = MethodType(self.myMethod.__func__, element)
有人可以解释一下 MethodType 实际上在做什么吗?为什么 func 标志 si 是必要的?
最佳答案
您正在使用 MethodType
将 Decorator
的 myMethod
方法绑定(bind)到另一个对象。这是行不通的,因为当您使用 self.myMethod 访问它时,您已经获得了一个绑定(bind)方法。第一个绑定(bind)将 Decorator
对象作为 self
传递,第二个绑定(bind)在尝试将 MyElement
实例作为第二个参数传递时引发异常。
有几种方法可以解决这个问题。目前尚不清楚哪一个最适合您,因为您的 myMethod
示例没有对 self
执行任何操作。
一种选择是通过 Decorator
类访问 myMethod
,而不是通过 self
。这意味着它将被解除绑定(bind)(当然,直到您将其包装在 MethodType
中)。在此版本中,myMethod
中看到的 self
值将是 MyElement
实例,而不是 Decorator
(这可能是让阅读代码的人感到惊讶)。在 Python 2 中,未绑定(bind)方法需要进行特殊检查以确保 self
的类型正确,因此这是行不通的。
def decorate(self, element):
element.myMethod = MethodType(Decorator.myMethod, element)
另一种选择是将使用 self.myMethod
获得的绑定(bind)方法保存为 element
上的变量,而不尝试再次绑定(bind)它。使用这种方法,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))
关于python - 使用 MethodType 将方法从一个实例动态添加到另一个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29841424/