比较包装函数是否是装饰器实例

时间:2019-05-31 02:05:49

标签: python python-3.x decorator python-decorators

我有decorator1decorator2函数。我正在用它们来装饰功能。

@decorator1("some", "args")
@decorator2(1,2)
@decorator1()
def my_func(): print("my func")

当我一遍又一遍地调用包装函数时,输出如下所示:

my_func.__wrapped__

decorator1
decorator2
decorator1
my func

my_func.__wrapped__.__wrapped__()

decorator2
decorator1
my func

问题在于每个包装函数的名称为my_func。我想检查此链中的某个函数是否为decorator1的实例。我想知道这一点,因为我将使用装饰器的参数。 (我已经通过使用__closure__单元格来了解它们。)

说明

我决定举个例子来说明我的目的。

@route("/index")
def index(): pass

@route("/settings")
@need_permission("admin")
def settings: pass

@route("/blog")
@need_permission("admin", "user")
def blog(): pass

我可以在所有其他地方获得所有这些路由功能,并且我想提取哪个需要哪个权限。

这是我的发现:

>>> blog()
route blog
permissions admin user
>>> blog.__closure__[0].cell_contents
('/blog',)
>>> blog.__closure__[1].cell_contents()
permissions admin user
>>> blog.__closure__[0].cell_contents.__closure__[0].cell_contents
('admin', 'user')
>>> blog.__closure__[0].cell_contents.__closure__[1].cell_contents()
>>> 

我只想提取持有权限的元组。我可以按某些特定顺序应用装饰器,并轻松提取它们,或者需要实现@Poolka指出的DecoratorApplier函数。如果没有办法像第一种选择那样知道,我将紧随其后。

1 个答案:

答案 0 :(得分:0)

instance of a decorator-用函数和常规函数实现的装饰器都是function类型的函数。

不确定要获得什么。下面的代码是我将如何解决该问题。基本上,我将属性primal_type添加到装饰狂欢节涉及的所有功能中,以存储功能/装饰器的名称。我使用另一个名为DecoratorApplier的装饰器执行此操作。该代码似乎执行与问题相关的操作。

编辑

增加的说明并不能使所有事情变得清晰。我猜想以这种方式混合函数和装饰器逻辑不是很好的方法。也许还有另一个选项可以在函数内部获取所需的信息?无论如何,下面是我原始方法的两个修改版本(oda代表可选的装饰器参数)。

(1)-带有DecoratorApplier

import functools


def decorator_1(*d1_args, **d1_kwargs):
    def decorator(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            print('inside decorator_1', d1_args, d1_kwargs)
            return func(*args, **kwargs)
        return wrapped
    return decorator


def decorator_2(*d2_args, **d2_kwargs):
    def decorator(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            print('inside decorator_2', d2_args, d2_kwargs)
            return func(*args, **kwargs)
        return wrapped
    return decorator


class DecoratorApplier:

    def __init__(self, *decorators):
        self.decorators = decorators

    def __call__(self, func):
        func.oda = dict()
        for decorator in self.decorators:
            func = decorator[0](*decorator[1], **decorator[2])(func)
            (
                func
                .oda
                .setdefault(decorator[0].__name__, list())
                .extend([decorator[1], decorator[2]])
            )
        return func


@DecoratorApplier(
    (decorator_1, (1, 2), {'x': 10, 'y': 20}),
    (decorator_2, tuple(), dict()))
def f_1():
    print('inside f_1')
    print(f_1.oda)
    return


if __name__ == '__main__':

    f_1()

(2)-修改原始装饰器

import functools


def decorator_1(*d1_args, **d1_kwargs):
    def decorator(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            print('inside decorator_1', d1_args, d1_kwargs)
            (
                kwargs
                .setdefault('oda', dict())
                .setdefault('decorator_1', list())
                .extend([d1_args, d1_kwargs])
            )
            return func(*args, **kwargs)
        return wrapped
    return decorator


def decorator_2(*d2_args, **d2_kwargs):
    def decorator(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            print('inside decorator_2', d2_args, d2_kwargs)
            (
                kwargs
                .setdefault('oda', dict())
                .setdefault('decorator_2', list())
                .extend([d2_args, d2_kwargs])
            )
            return func(*args, **kwargs)
        return wrapped
    return decorator


@decorator_1(1, 2, x=10, y=20)
@decorator_2()
def f_1(oda=None):
    print('inside f_1')
    print('    oda', oda)
    return


if __name__ == '__main__':

    f_1()