Как я могу использовать переменную экземпляра класса в качестве аргумента для декоратора метода в Python?

StackOverflow https://stackoverflow.com/questions/1231950

  •  22-07-2019
  •  | 
  •  

Вопрос

Как я могу использовать переменную экземпляра класса в качестве аргумента для декоратора метода в 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()
Это было полезно?

Решение

Это не сработает; декоратор вызывается во время создания класса , то есть задолго до создания экземпляра ( if , который когда-либо происходит). Так что если ваш " декоратор " нужен экземпляр, вам нужно сделать «украшение» во время создания экземпляра:

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 .

Другие советы

Ваша функция «warper» на самом деле является декоратором, а не деформатором.Ваша функция «decorator1» — это конструктор-декоратор.Если вы хотите иметь доступ к self.var1 во время выполнения, вам нужно сделать деформатор, а не декоратор:

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")

Декоратор выполняется, когда класс определен, поэтому вы не можете передать ему переменную экземпляра.

Вот как мы делали это в старину.

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 , чтобы воспользоваться преимуществами " обертывания " ;. Сделано по-старому, без каких-либо с оператором .

Да, это многословно. Тем не менее, он также не содержит никакой магии.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top