说我有一个这样的装饰器:
def repeat(repeat_count):
def decorator(func):
def wrapped(self):
for X in range(repeat_count):
func() # Do Function
return wrapped
return decorator
和这样的课程
class SomeClass(object):
def __init__(self, do_count):
self.some_method = repeat(do_count)(self.some_method)
def some_method(self):
print("I'm Doing Something")
因为装饰器只返回一个方法,所以很明显这是可行的。但是,它从类实例中取消了some_method函数的绑定,所以我无法再执行以下操作:
>>> sc = SomeClass(10)
>>> sc.some_method()
# TypeError: wrapped() missing 1 required positional argument: 'self'
我得到一个例外,因为自身不再自动传递。为了使这项工作,我可以简单地做到这一点:
sc.some_method(sc)
但我宁愿不要。有什么方法可以将方法重新绑定到实例,最好不用任何额外的导入(如TypeMethod)就可以完成。
答案 0 :(得分:2)
我得到一个例外,因为自身不再自动传递。
实际上,它仍然会自动传递。之所以会出现此异常,是因为您定义装饰器的方式要求将其传递两次。
在包装的运行时中,func
已绑定(即,它已经自传递)。通过定义wrapped
来接受一个位置参数,您需要再次传递self
,这就是sc.some_method(sc)
正常工作的原因。 self
根据需要传递两次-隐式传递一次,显式传递一次。
对代码的最小修复是从self
的签名中删除wrapped
,因为根据self.some_method
绑定中的描述符协议,该签名已隐式传递。
def repeat(repeat_count):
def decorator(func):
def wrapped():
for X in range(repeat_count):
func() # Do Function
return wrapped
return decorator
但是,这并不是真正的最佳解决方案。您将需要接受*args
和**kwargs
,以便无论装饰函数的签名如何,都可以应用装饰器:
def repeat(repeat_count): # <-- the "decorator maker"
def decorator(func): # <-- the decorator
def wrapped(*args, **kwargs): # <-- this will replace "func"
for X in range(repeat_count):
func(*args, **kwargs) # <-- note: pass along the arguments!
return wrapped # <-- note: no call here!
return decorator
答案 1 :(得分:1)
在一个非常简单的情况下,您不需要从装饰器本身访问self
,您可以简单地使用以下命令(这几乎就是您已经做的事,减去包装函数的调用,以及self
的通过)。
分配时,传递给装饰器的方法已经绑定到self
self.some_method = repeat(do_count)(self.some_method)
完整代码:
def repeat(repeat_count):
def decorator(func):
def wrapped():
for X in range(repeat_count):
func()
return wrapped
return decorator
class SomeClass(object):
def __init__(self, do_count):
self.a = 3
self.some_method = repeat(do_count)(self.some_method)
def some_method(self): print("Accesing my a from inside: %d" % self.a)
sc = SomeClass(5)
sc.some_method()
输出:
Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3