Использование параматеризованного декоратора для записи методов в классе - PullRequest
0 голосов
/ 14 февраля 2020

Я понимаю, что много чернил уже пролилось на декораторов, но я не могу найти другой вопрос, который точно охватывает это. У меня есть класс, и я хотел бы пометить некоторые методы в этом классе с помощью декоратора. Теоретически это просто, поскольку декораторы запускаются, когда класс определен. Однако мне также нужно записать некоторые введенные пользователем параметры из этого декоратора. Так что-то вроде этого:

@classmethod
def record_func(cls, is_function_special):
    def wrapped(func):
        return func 
    cls.recorded_functions.append((func, is_function_special))
    return wrapped

class TestClass:
    recorded_functions = []

    @record_func(False)
    def func1():
        return 1

    @get_funcs(True)
    def func2():
        return 2

Идея заключается в том, что я мог бы использовать это TestClass.recorded_functions в другом месте.

Проблема (может быть, одна из многих) заключается в том, что это только декоратор внешнего уровня (в данном случае, record_fun c, а не обернутый), который запускается при определении класса, который имеет аргумент в своем пространстве имен, но не в функции. Есть ли какой-нибудь умный способ записать и аргумент и функцию?

Примечание: в этом примере я сделал декоратор методом класса, чтобы его можно было распространять на другие классы.

Любая помощь приветствуется.

1 Ответ

1 голос
/ 14 февраля 2020

Мне нравится эта проблема, я работал над пакетом декоратора и думаю, что это может быть отличным дополнением. Тем не менее, дайте мне знать, если это приведет вас в правильном направлении. Он может записывать каждый вызов метода, записывать его аргументы и kwargs. Затем вы можете выполнить любую аналитику / агрегацию с теми результатами, которые вам нужны.

import functools


def bvr_start(arg=None):
    def bvr_start_decorator(func):
        @functools.wraps(func)
        def bvr_start_wrapper(*args, **kwargs):
            msg = ("STARTED | "
                   "FUNCTION: {} | "
                   "ARGS: {} | "
                   "KWARGS: {} ").format(func.__name__,
                                         args,
                                         kwargs)

            args[0].called_functions.append(msg)


            print(msg)

            return_value = func(*args, **kwargs)
            return return_value
        return bvr_start_wrapper

    if callable(arg):
        return bvr_start_decorator(arg)

    return bvr_start_decorator


class Hello:

    called_functions = []

    @bvr_start
    def test_function_one(self):
        print("Inside my function one")

    @bvr_start
    def test_function_two(self, x):
        print("Inside my function two")


    @bvr_start
    def test_function_three(self, y):
        print("Inside my function three")

hello = Hello()

hello.test_function_one()
hello.test_function_two(4)
hello.test_function_three(y=5)

print("Now print out your called functions")

for called_function in hello.called_functions:
    print(called_function)

Теперь результат этого:

STARTED | FUNCTION: test_function_one | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {} 
Inside my function one

STARTED | FUNCTION: test_function_two | ARGS: (<__main__.Hello object at 0x1038ef2d0>, 4) | KWARGS: {} 
Inside my function two

STARTED | FUNCTION: test_function_three | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {'y': 5} 
Inside my function three

Теперь распечатайте вызванные вами функции

STARTED | FUNCTION: test_function_one | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {} 

STARTED | FUNCTION: test_function_two | ARGS: (<__main__.Hello object at 0x1038ef2d0>, 4) | KWARGS: {} 

STARTED | FUNCTION: test_function_three | ARGS: (<__main__.Hello object at 0x1038ef2d0>,) | KWARGS: {'y': 5}

Теперь у вас есть запись функции и аргумент. И вы можете сделать еще несколько таких изменений, как форматирование в последнем списке named_functions, чтобы подсчитать, сколько раз каждый вызывался с чем!

Спасибо, и дайте мне знать, если это поможет!

...