Python 如何在不丢失方法绑定状态的情况下动态修饰类方法?
假设我有一个这样的装饰师:Python 如何在不丢失方法绑定状态的情况下动态修饰类方法?,python,python-3.x,Python,Python 3.x,假设我有一个这样的装饰师: 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 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'
我得到一个异常,因为self不再自动传递。为了实现这一目标,我可以简单地做到:
sc.some_method(sc)
但我宁愿不要。是否有任何方法可以将方法重新绑定到实例,最好不需要任何额外的导入(如TypeMethod)就可以完成
我得到一个异常,因为self不再自动传递
实际上,它仍然是自动传递的。出现此异常是因为定义装饰器的方式要求它被传递两次
在wrapped的运行时中,func
已经绑定(即它已经自我传递)。通过定义wrapped
来接受一个位置参数,您需要再次传入self
,这就是sc的原因。某些方法(sc)
工作正常。self
根据需要传递两次-一次隐式传递,一次显式传递
对代码的最小修复是从wrapped
的签名中删除self
,因为该签名已根据self.some\u方法的绑定中的描述符协议隐式传递
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
def repeat(repeat_count):#对于一个相当简单的情况,您不需要从decorator本身访问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
对不起,那是个打字错误。这只是一个例子。在我实际做的事情中,我使用了args和kwargs,所以不用担心。如果你在正确的位置使用*args和**kwargs,那么你一开始就不会有错误,所以…@wim如果我想通过使用包装的范围访问实例的某些属性,该怎么办?我试图在SomeClass
的\uuuuu init\uuuuuu
中设置以下内容:self.some\u方法=重复(do\u计数)(SomeClass.some\u方法)
并将self
作为位置参数添加到wrapped
函数中。尽管如此,调用sc=SomeClass(5)sc.some_method()
会导致与@MohsinKale'相同的错误s@EliranAbdoo在wrapped
内部,实例可以作为func.\uuuuu self\uuuuu
使用。我所做的只是在返回它时调用wrapped方法。这只是我在不到3分钟内写的一个例子,让我放松一下。至于repost声明,我已经明确表示,我更愿意避免任何额外的导入,因为您链接到的帖子中给出了主要的解决方案。这个问题的答案不需要任何导入。使用“动态修饰”是指在init方法中显式修饰(或者至少不使用@syntax)?正如@wim所说的-请不要进行使您收到的答案无效的编辑。谢谢。@JonClements很不幸,现在的答案中不再提到问题,但答案没有回答Moshin想问的问题。他没有通过编辑来改变他的问题,而是进行了编辑以使问题更清楚。因为打字错误而不得不提出一个新问题对我来说似乎毫无帮助。