简体   繁体   English

通过从内部装饰器调用 class 方法修改 class 属性

[英]Modifying class attribute by calling class method from inside decorator

I have quite a few methods that requires opening some file (each method has different), doing some stuff, closing it.我有很多方法需要打开一些文件(每种方法都有不同),做一些事情,关闭它。 Althou it is possible to open and close a file within each method, I am wondering whether it is possible to do it through decorators so that a decorator could take method as a parameter which would load data into obj attribute that the decorated class is acting on.虽然可以在每个方法中打开和关闭文件,但我想知道是否可以通过装饰器来完成,以便装饰器可以将方法作为参数,将数据加载到装饰的 class 正在作用的 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
    

My question is whether this is even possible and are there better ways to approach it?我的问题是这是否可能,是否有更好的方法来解决它?

Well, you can do something similar to that, but you'd need to pass the name the method to the decorator because there's no self for it to refer to when it's used to decorate the method(s) — which happens when the class is defined not when the code in it is executed afterwards.好吧,您可以做类似的事情,但是您需要将方法的名称传递给装饰器,因为当它用于装饰方法时没有self可以引用 - 当 class 是之后执行其中的代码时未定义。

Here's what I mean:这就是我的意思:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM