python - 如何动态修饰类方法,同时不丢失方法绑定状态?
问题描述
假设我有一个这样的装饰器:
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 不再自动传递。
实际上,它仍然是自动通过的。你得到这个异常是因为你定义装饰器的方式要求它被传递两次。
从包装的运行时内,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
推荐阅读
- ms-access - 如何通过 VBA 代码连接控件及其标签?
- robotium - 机器人录音失败
- laravel-5 - 拉拉维尔 | 更新查询返回 "[{"laboratory":"Boulanger"}]" 作为值而不是 "Boulanger"
- build - 如何将 azure devops 构建复制到本地计算机
- c# - Asp.net mvc ADD 认证账户控制器
- python - 似乎无法将时间戳与 Python 中创建的日期范围相匹配
- android - 将 ClickListener 附加到列表项按钮单击自定义适配器
- log4net - 无法使用来自 GCE 实例的最新版本的 google.cloud.logging.log4net 将日志发送到 Stackdrvier
- node.js - 节点js中的对象数组变为空白
- excel - 再次,从网站接收数据的操作?