【问题标题】:Modifying class attribute by calling class method from inside decorator通过从装饰器内部调用类方法来修改类属性
【发布时间】:2021-03-17 00:40:22
【问题描述】:

我有很多方法需要打开一些文件(每种方法都有不同),做一些事情,关闭它。尽管可以在每个方法中打开和关闭文件,但我想知道是否可以通过装饰器来实现,以便装饰器可以将方法作为参数,将数据加载到装饰类正在作用的 obj 属性中.

class Foo:
    def __init__(self, fname):
        self.fname = fname

    def load_file(self):
        with open(self.fname, 'rb') as f:
            self.file_ = pickle.load(f)
    
    def do_some_work(self):
        self.load_file()
        ... # some calculation and so on
        delattr(self, 'file_')

    @loader(self.load_file)
    def do_some_work_decorated(self):
         ... # only some calculation and so on, file loading is done by the defined method in decorator
    

我的问题是这是否可能,有没有更好的方法来解决它?

【问题讨论】:

  • 我看到你已经为你的问题发布了一个答案,但我真的不认为你已经描述了你到底想要做什么(除了“试图通过装饰方法”)。是不是你想用装饰器做的文件的打开和处理和关闭?你能详细说明一下吗?
  • @fountainhead:我认为这个问题很清楚——OP 希望在多种方法的开头进行一些常见的预处理,并想知道是否有办法使用装饰器来实现。我同意这似乎是一个奇怪的问题,因为这样做比在需要它的开头显式调用方法要多得多——所以也许它是一个XY Problem

标签: python python-3.x oop python-decorators contextmanager


【解决方案1】:

好吧,你可以做类似的事情,但是你需要将 name 方法传递给装饰器,因为它没有 self 来引用它何时用于装饰方法——在定义类时发生,而不是在之后执行其中的代码时发生。

这就是我的意思:

import pickle

def loader(do_stuff):
    def decorator(method):
        def decorated(self, *args, **kwargs):
            getattr(self, do_stuff)()  # Call specified class method.
            return method(self, *args, **kwargs)  # Then call decorated method.
        return decorated
    return decorator


class Foo:
    def __init__(self, fname):
        self.fname = fname

    def load_file(self):
        with open(self.fname, 'rb') as f:
            self.file_ = pickle.load(f)

    def do_some_work(self):
        self.load_file()
        ... # some calculation and so on
        delattr(self, 'file_')

    @loader('load_file')
    def do_some_work_decorated(self):
        ... # only some calculation and so on, file loading is done by the defined method in decorator
        print(f'{self.file_}')

if __name__ == '__main__':

    # Create a test file.
    with open('foo.pkl', 'wb') as outp:
        pickle.dump(42, outp)

    # See if decorator worked.
    foo = Foo('foo.pkl')
    foo.do_some_work_decorated()  # -> 42

【讨论】:

猜你喜欢
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 2018-08-31
  • 1970-01-01
相关资源
最近更新 更多