如何解决通过装饰器向类动态添加功能
我正在尝试找到一种通过装饰器向类中动态添加方法的方法。 装饰器我看起来像:
def deco(target):
def decorator(function):
@wraps(function)
def wrapper(self,*args,**kwargs):
return function(*args,id=self.id,**kwargs)
setattr(target,function.__name__,wrapper)
return function
return decorator
class A:
pass
# in another module
@deco(A)
def compute(id: str):
return do_compute(id)
# in another module
@deco(A)
def compute2(id: str):
return do_compute2(id)
# **in another module**
a = A()
a.compute() # this should work
a.compute2() # this should work
我希望装饰者应该向类A添加compute()
函数,A的任何对象都应该具有compute()方法。
但是,在我的测试中,这仅在我将计算明确地导入创建A对象的位置时有效。我认为我缺少明显的东西,但不知道如何解决。感谢您的帮助!
解决方法
我认为使用作为类实现的装饰器会更简单:
class deco:
def __init__(self,cls):
self.cls = cls
def __call__(self,f):
setattr(self.cls,f.__name__,f)
return self.cls
class A:
def __init__(self,val):
self.val = val
@deco(A)
def compute(a_instance):
print(a_instance.val)
A(1).compute()
A(2).compute()
输出
1
2
但是仅仅因为您可以做到,并不意味着您应该这样做。这可能会成为调试的噩梦,并且可能会给任何静态代码分析器或linter带来麻烦(例如,PyCharm会与Unresolved attribute reference 'compute' for class 'A'
“抱怨”)
当我们将其拆分为不同的模块时,为什么它不能立即使用(更具体地说,在另一个模块中定义了compute
时)?
假设以下内容:
a.py
print('importing deco and A')
class deco:
def __init__(self,val):
self.val = val
b.py
print('defining compute')
from a import A,deco
@deco(A)
def compute(a_instance):
print(a_instance.val)
main.py
from a import A
print('running main')
A(1).compute()
A(2).compute()
如果执行main.py
,我们将得到以下信息:
importing deco and A
running main
Traceback (most recent call last):
A(1).compute()
AttributeError: 'A' object has no attribute 'compute'
缺少某些内容。 defining compute
未输出。更糟糕的是,从未定义compute
,更不用说绑定到A
了。
为什么?因为没有任何事情触发b.py
的执行。仅仅因为它坐在那里并不意味着它就会被执行。
我们可以通过导入来强制执行它。对我来说有点儿侮辱,但之所以有效,是因为导入文件具有副作用:它执行不受if __name__ == '__main__
保护的每一段代码,就像导入模块会执行其__init__.py
文件一样
main.py
from a import A
import b
print('running main')
A(1).compute()
A(2).compute()
输出
importing deco and A
defining compute
running main
1
2
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。