【问题标题】:Inside a decorator-class, access instance of the class which contains the decorated method在装饰器类中,访问包含装饰方法的类的实例
【发布时间】:2011-06-26 15:01:50
【问题描述】:

我有以下装饰器,在调用@saveconfig装饰的方法后保存配置文件:

class saveconfig(object):
    def __init__(self, f):
        self.f = f

    def __call__(self, *args):
        self.f(object, *args)
        # Here i want to access "cfg" defined in pbtools
        print "Saving configuration"

我在下面的类中使用这个装饰器。调用createkvm方法后,配置对象self.cfg应该保存在装饰器内部:

class pbtools()
    def __init__(self):
        self.configfile = open("pbt.properties", 'r+')
        # This variable should be available inside my decorator
        self.cfg = ConfigObj(infile = self.configfile)

    @saveconfig
    def createkvm(self):
        print "creating kvm"

我的问题是我需要访问装饰器saveconfig 内的对象变量self.cfg。第一种天真的方法是向保存对象的装饰器添加一个参数,例如@saveconfig(self),但这不起作用。

如何访问装饰器内方法宿主的对象变量?我是否必须在同一个类中定义装饰器才能访问?

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    你也可以使用一个简单的函数来实现你想要的:

    def saveconfig(f):
        # this method replaces the decorated, so `self` will be the pbtools instance
        def wrapped(self, *args):
            f(self, *args)
            # Here i want to access "cfg" defined in pbtools
            print "Saving configuration", self.cfg
        return wrapped
    

    如果saveconfig 必须是一个类,那么您需要 Sven 的解决方案。

    【讨论】:

    • 未命中 functools.wraps。此外,它会破坏空函数(例如,没有参数的非方法),并且通常对于非方法的第一个参数具有误导性名称 - 最好将 self 留在 args 中;)(在这些更改之后,它很漂亮我已经发布了很多内容)
    【解决方案2】:

    您将 object 作为 self 传递给装饰方法。问题是,你不能轻易获得self,因为 Python 看到了修饰的方法,它现在是一个对象,并且不认为它是一个方法(调用时应该传递self - 或者,更一般地说,这应该作为返回绑定方法的属性)。正如@Sven Marnach 所指出的,您可以解决这个问题。

    但是,您可以在没有类的情况下使用闭包轻松重写此装饰器(有点短,也解决了上述问题):

    def saveconfig(f):
        @functools.wraps(f) # to preserve name, docstring, etc.
        def wrapper(*args, **kwargs): # **kwargs for compability with functions that use them
            f(*args, **kwargs)
            # save config
        return wrapper
    

    其他说明:

    • 术语混淆:示例中没有类变量。就方法定义而言,类变量将缩进x = ...,并在所有实例之间共享(具体而言,它将是pbtools 对象的属性)-self 上的所有内容都是实例属性。
    • 在类定义时(当您定义方法、应用装饰器等时)没有self

    【讨论】:

    • 如果省略object 参数,代码将不再运行。试试看。
    • @Sven:似乎只有基于类的方法。您可能需要说服 Python 将该对象视为一种方法(因此会生成一个隐式传递 self 的 getter)=/ 好吧,还有一个不使用它的原因。
    【解决方案3】:

    您必须使您的装饰器类表现为descriptor 才能访问该实例:

    class saveconfig(object):
        def __init__(self, f):
            self.f = f
    
        def __get__(self, instance, owner):
            def wrapper(*args):
                print "Saving configuration"
                print instance.cfg
                return self.f(instance, *args)
            return wrapper
    

    您的代码将object 作为第一个参数传递给self.f(),它应该在其中传递pbtools 实例。

    【讨论】:

      猜你喜欢
      • 2019-02-03
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      相关资源
      最近更新 更多