在类中使用装饰器访问self中的属性

时间:2019-02-01 16:27:45

标签: python python-decorators

我有一个为顺序数据处理管道提供一些通用结构的类。我想定时执行一个方法,并将其保存到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 :(得分:1)

您的@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调用。