如何在Python中将类实例变量作为方法装饰器的参数?

10 投票
6 回答
10105 浏览
提问于 2025-04-15 13:23

我想知道在Python中,如何把一个类的实例变量当作方法装饰器的参数来用。下面是一个简单的例子,展示了我想做的事情。显然,这样做是失败的,因为装饰器函数无法访问到实例的引用,我不知道该如何从装饰器中获取这个引用。

def decorator1(arg1):
    def wrapper(function):
        print "decorator argument: %s" % arg1
        return function
    return wrapper

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1

    @decorator1(self.var1)
    def method1(self):
        print "method1"

foo = Foo("abc")
foo.method1()

6 个回答

1

这是我们以前是怎么做的。

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1

    def method1(self):
        self.lock()
        try:
            self.do_method1()
        except Exception:
            pass # Might want to log this
        finally:
            self.unlock()

    def do_method1(self):
        print "method1"

    def lock(self):
        print "locking: %s" % self.arg1

    def unlock(self):
        print "unlocking: %s" % self.arg1

现在,一个子类只需要重写 do_method1 就能享受到“包装”的好处。这样做是老办法,没有用到任何 with 语句。

是的,这样写比较啰嗦。不过,它也没有什么神秘的地方。

9

你的“warper”函数其实是一个装饰器,而不是一个真正的“warper”。你的“decorator1”函数是一个装饰器的构造函数。如果你想在运行时访问self.var1,你需要做一个warper,而不是装饰器:

def decorator(function):
  def wrapper(self,*args,**kwargs):
    print "Doing something with self.var1==%s" % self.var1
    return function(self,*args,**kwargs)
  return wrapper

class Foo(object):
  def __init__(self, arg1):
    self.var1 = arg1

  @decorator
  def method1(self):
    print "method1"

foo = Foo("abc")
foo.method1()

如果你想要一个更通用的装饰器,最好是声明一个可调用的类:

class decorator:
  def __init__(self,varname):
      self.varname = varname
  def __call__(self,function):
    varname=self.varname
    def wrapper(self,*args,**kwargs):
      print "Doing something with self.%s==%s" % (varname,getattr(self,varname))
      return function(self,*args,**kwargs)
    return wrapper

使用:

  @decorator("var1")
11

这段话的意思是,装饰器在创建类的时候就会被调用,这个时间点是在实例被创建之前(如果有创建的话)。所以如果你的“装饰器”需要用到实例,那你就得在实例创建的时候进行“装饰”。

def get_decorator(arg1):
    def my_decorator(function):
        print "get_decorator argument: %s" % arg1
        return function
    return my_decorator

class Foo(object):
    def __init__(self, arg1):
        self.var1 = arg1
        self.method1 = get_decorator(self.var1)(self.method1)

    def method1(self):
        print "method1"

foo = Foo("abc")
foo.method1()

另外,我把函数的名字改成了更符合它们意思的名称;在你的例子中,真正的“装饰器”,也就是那个可能会修改方法的函数,其实是 wrapper,而不是 decorator1

撰写回答