是否有一种pythonic方法可以在子类的方法上跳过装饰?

时间:2016-02-02 23:17:34

标签: python flask decorator flask-restful

我有一个类使用另一个库中的装饰器来装饰一些方法。具体来说,类子类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

3 个答案:

答案 0 :(得分:9)

Flask-HTTPAuthAppBundle\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)