Как я могу использовать переменную экземпляра класса в качестве аргумента для декоратора метода в Python?
Вопрос
Как я могу использовать переменную экземпляра класса в качестве аргумента для декоратора метода в 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
, чтобы воспользоваться преимуществами " обертывания " ;. Сделано по-старому, без каких-либо с оператором
.
Да, это многословно. Тем не менее, он также не содержит никакой магии.