Python метод декоратор, который модифицирует класс - PullRequest
0 голосов
/ 16 марта 2020

По сути, мне нужно отслеживать методы, которые я обертываю этим декоратором, чтобы использовать позже при редактировании исходного объекта. Код работает, если я вызываю метод, но если нет, код в обертке никогда не выполняется. Оболочка - единственное место, где я получаю объект, где я могу его изменить. Итак, мне нужен какой-то другой способ изменить объект без вызова метода, который я в нем декорирую.

Я пробовал так много разных способов, но просто не могу заставить это работать.

import functools

def decorator3(**kwargs):
    print(1)
    def decorator(function):
        print(2)
        @functools.wraps(function)
        def wrapper(self, *args):
            print(3)
            self.__test__ = "test worked"
            function(self, *args)
        return wrapper
    return decorator

class Test:
  def __init__(self):
    self.a = "test"

  @decorator3()
  def test(self):
    print(self.a)

t = Test()
#t.test()
print(t.__test__)

1 Ответ

0 голосов
/ 19 марта 2020

Ваши части кода выполняются в разное время.

Функция внешнего декоратора, где вы печатаете «1», вызывается там, где вы читаете @decorator3(). Результат вызова этой функции, decorator, затем немедленно применяется к декорированной функции (соответственно, метод), где вы читаете "2".

В вашем случае внутренний декоратор заменяет метод на другая функция, которая вызывает оригинальный метод. Только если вы вызовете это, вы достигнете «3».

Итак:

  • в 1, вы ничего не знаете о своей функции.
  • в 2 вы знаете свою функцию, но не в каком классе она живет.
  • в 3, вы знаете свой объект, но только если вызывается ваша функция.

Вам нужно решить что именно вы хотите сделать: согласно вашему описанию, вы хотите пометить функции. Это то, что вы прекрасно можете сделать в «2».

Вы говорите:

Мне нужно отслеживать методы, которые я позже украсил в коде. По сути, я украшаю его, чтобы «пометить» метод, и у меня есть несколько классов с разными методами, которые мне нужно пометить. Я буду вызывать decorator3 в других классах, поэтому я не вижу, как поможет установка декоратора в init . Редактируя исходный класс, я позже могу поместить метод в словарь, который, как я надеялся, сделает декоратор.

Может быть, работает следующее:

import functools

def method_flagger(function):
    function._flag = "flag"
    return function

list_of_methods = []

def flag_reader(function):
    @functools.wraps(function)
    def wrapper(self, *args):
        for i in dir(self.__class__):
        #for i, j in self.__class__.__dict__.items():
            method_wrapper = getattr(self, i)
            if hasattr(getattr(self, i), "_flag"):
                list_of_methods.append((self, i))
        return function(self, *args)
    return wrapper

class Test:
    @flag_reader
    def __init__(self):
        self.a = "test"

    @method_flagger
    def test(self):
        print(self.a)

    @method_flagger
    def test2(self):
        print(self.a)

t1 = Test()
t2 = Test()
#t.test()
#print(t.__test__)

print(list_of_methods)

Это дает мне вывод

[(<__main__.Test object at 0x000001D56A435860>, 'test'), (<__main__.Test object at 0x000001D56A435860>, 'test2'), (<__main__.Test object at 0x000001D56A435940>, 'test'), (<__main__.Test object at 0x000001D56A435940>, 'test2')]

, поэтому для каждого экземпляра затронутого объекта и каждой украшенной функции мы получаем кортеж, обозначающий их обоих.

...