我有一个类使用另一个库中的装饰器来装饰一些方法。具体来说,类子类flask-restful资源,用httpauth.HTTPBasicAuth().login_required()
修饰http方法,并在模型服务上做一些合理的默认设置。
在大多数子类中,我想要应用装饰器;因此我宁愿删除它而不是在子类中添加它。
我的想法是拥有一个执行操作的私有方法和一个装饰的公共方法。通过重写公共方法来调用私有方法而不是装饰此覆盖,可以避免装饰的影响。下面的模拟示例。
我很想知道是否有更好的方法来做到这一点。在python中有“取消装饰器”的快捷方式可以产生这种效果吗?
或者你能推荐一种更好的方法吗?
其他一些问题对此有适当的答案,例如: Is there a way to get the function a decorator has wrapped?。但我的问题是关于更广泛的设计 - 我感兴趣的是任何 pythonic方式在装饰方法中运行操作而没有装饰效果。例如。我的例子是这样的,但可能还有其他的。
def auth_required(fn):
def new_fn(*args, **kwargs):
print('Auth required for this resource...')
fn(*args, **kwargs)
return new_fn
class Resource:
name = None
@auth_required
def get(self):
self._get()
def _get(self):
print('Getting %s' %self.name)
class Eggs(Resource):
name = 'Eggs'
class Spam(Resource):
name = 'Spam'
def get(self):
self._get()
# super(Spam, self)._get()
eggs = Eggs()
spam = Spam()
eggs.get()
# Auth required for this resource...
# Getting Eggs
spam.get()
# Getting Spam
答案 0 :(得分:9)
Flask-HTTPAuth在AppBundle\Entity\AcmeEntity:
properties:
# ...
code:
- App\Bundle\MyBundle\Validator\Constraints\Code: ~
装饰器中使用functools.wraps
:
login_required
从Python 3.2开始调用update_wrapper
,您可以通过def login_required(self, f):
@wraps(f)
def decorated(*args, **kwargs):
...
访问原始函数:
允许访问原始函数以进行内省和其他 目的(例如绕过缓存装饰器,如
__wrapped__
), 此函数会自动将lru_cache()
属性添加到 包装器引用被包装的函数。
如果您正在编写自己的装饰器,就像在您的示例中一样,您也可以使用__wrapped__
来获得相同的功能(以及保留文档字符串等)。
另见Is there a way to get the function a decorator has wrapped?
答案 1 :(得分:2)
另一个常见的选择是让装饰函数保留可以访问的原始函数的副本:
def auth_required(fn):
def new_fn(*args, **kwargs):
print('Auth required for this resource...')
fn(*args, **kwargs)
new_fn.original_fn = fn
return new_fn
现在,对于任何已装饰的函数,您可以访问其original_fn
属性以获取原始未装饰函数的句柄。
在这种情况下,您可以定义某种类型的调度程序,它可以进行普通函数调用(当您对装饰器行为感到满意时),也可以在您希望避免装饰器行为时调用thing.original_fn
。
您提出的方法也是构建它的有效方法,我的建议是否“更好”取决于您正在处理的其余代码,谁需要阅读它以及其他类型的权衡。
答案 2 :(得分:0)
我很想知道是否有更好的方法来做到这一点。有没有 在python中“取消装饰器”的快捷方式会产生这种效果吗?
使用undecorated库。它遍历所有装饰器并返回原始函数。文档应该是不言自明的,基本上你只需要调用:undecorated(your_decorated_function)