Сравнение упакованной функции, является ли она экземпляром декоратора - PullRequest
2 голосов
/ 31 мая 2019

У меня есть decorator1 и decorator2 функции.И я использую их для украшения функции.

@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()
>>> 

Я просто хочу извлечь кортежи, которыедержать разрешения.Я могу применять свои декораторы в каком-то определенном порядке и легко извлекать их, или мне нужно реализовать мою DecoratorApplier функцию, как указано @Poolka.Если нет способа узнать как первый вариант, я последую за вторым.

1 Ответ

0 голосов
/ 31 мая 2019

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...