首页 > 解决方案 > 如何在 python 烧瓶应用程序中外部化装饰器

问题描述

我编写了一个 python Flask 应用程序,它有一个类和方法如下。

class PythonSample:
    def method1():
        pass # does something

    def method2():
        pass # does something

现在我编写了另一个具有如下装饰器功能的类。

class PythonAuth:
    def oauthAuth():
        pass

现在我正在为 PythonSample 类的所有方法连接 oauthAuth 装饰器,如下所示

import oauthAuth from PythonAuth

class PythonSample
    @oauthAuth
    def method1():
        pass # does something

    @oauthAuth
    def method2():
        pass # does something

在每种方法上应用装饰器都可以正常工作。

问题:而不是将 oauthAuth 装饰器应用于每个方法。有没有办法在 python 中配置,将 oauthAuth 装饰器应用于类中的所有方法并排除某些方法。

诸如包含某些 URL 的身份验证和排除某些 URL 的身份验证之类的东西

请忽略此处 python 代码的语法。

标签: pythonauthenticationoauthpython-decoratorsexternalizing

解决方案


You can use a class decorator plus some magic.

Decorating Functions

Assume you have a decorator that just logs a string before calling the function.

def log(func):
    def logged_func(*args, **kwargs):
            print('logged')
            func(*args, **kwargs)
    return logged_func

Decorating classes

You can use the same trick, but with a class. log_all is a class decorator, cls is a class type. We use vars to walk the class dictionary, and look for methods by using callable(v). Decorate the method with log(v) and use setattr to change the cls definition to the new decorated method. Just like function decorators, return the class in the end.

def log_all(cls):
    for k, v in vars(cls).items():
            if callable(v):
                    setattr(cls, k, log(v))
    return cls

I am ignoring k essentially, but k is the method name, you could leverage it to achieve your usage scenario.

Full code

Here is a full example, that should make some sense now.

def log(func):
    def logged_func(*args, **kwargs):
            print('logged')
            func(*args, **kwargs)
    return logged_func

def log_all(cls):
    for k, v in vars(cls).items():
            if callable(v):
                    setattr(cls, k, log(v))
    return cls

@log_all
class A:
    def method(self):
            pass

Every method in class A should be decorated with the log decorator.

>>> a = A()
>>> a.method()
logged

推荐阅读