Использование декоратора в классе для доступа к атрибуту в себе - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть класс, который предоставляет некоторую общую структуру для последовательного конвейера обработки данных.Я хотел бы рассчитать время выполнения метода и сохранить его в атрибуте словаря self (self.timings).

from functools import wraps
import time

class Pipeline(object):

    def __init__(self):
        self.steps = {}
        self.timings = {}

    # Decorator for adding functions to pipeline
    def step(self, step_name):
        def step_decorator(f):
            self.steps[step_name] = f
        return step_decorator

    # Decorator for timing a step
    def time_step(f):
        @wraps(f)
        def timed(*args, **kwargs):
            start = time.time()
            result = f(*args, **kwargs)
            end = time.time()
            self.timings[f.__name__] = end - start
            return result
        return timed

    @time_step
    def example_method(self):
        if 'example_func' in self.steps:
            self.output = self.steps['example_func']()

Я могу создать конвейер и добавить к нему шаг:

pipeline = Pipeline()

@pipeline.step('example_func')
def example_func():
    for i in range(10000):
        pass
    return 'Completed!'

Но когда я пытаюсь запустить pipeline.example_method(), он не может получить доступ к self:

pipeline.example_method()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-54-8204774a5649> in <module>()
----> 1 pipeline.example_method()

<ipython-input-51-ffb2e95a110a> in timed(*args, **kwargs)
     21             result = f(*args, **kwargs)
     22             end = time.time()
---> 23             self.timings[f.__name__] = end - start
     24             return result
     25         return timed

NameError: name 'self' is not defined

Я попытался добавить self к параметрам в определении time_step, ноэто вызывает другую ошибку.Есть ли простой способ доступа к атрибутам из декорированного метода?

1 Ответ

0 голосов
/ 01 февраля 2019

Ваш @time_step() декоратор не является связанным методом, когда @time_step запускается, это просто функциональный объект.В функции не определено ни self, ни определено в оболочке, которую возвращает этот декоратор.

Если вы используете time_step() только для методов, то вы можете рассчитывать на то, что возвращаемая функция-оболочка будет связана (в этом случае это просто еще один объект функции в теле класса, поэтому он обрабатывается так же, как любая другая функция, присоединенная к классу и ищущая экземпляр):

def time_step(f):
    @wraps(f)
    def timed(self, *args, **kwargs):
        start = time.time()
        result = f(self, *args, **kwargs)
        end = time.time()
        self.timings[f.__name__] = end - start
        return result
    return timed

Обратите внимание, что вам нужно передать self аргумент для вызова f(), поскольку f также не связан.

...