Вы применяете свой декоратор к выходу декоратора @property
.Этот декоратор создает объект property()
, а не функцию.Это потому, что декораторы применяются наружу из определения функции;см. мой ответ о порядке выполнения декоратора ;поэтому сначала применяется @safe_property
, затем @property
, затем @my_decorator
.
Если вы хотите украсить функцию получения, поместите ваш декоратор прямо над оператором def
, он будет выполнен первыми все, что возвращает ваш декоратор, будет передано декоратору safe_property()
(который добавляет свою собственную функцию-обертку):
@property
@safe_property
@my_decorator
def do_func(self):
print("inside do_func!")
return [2,3,4]
или, если смотреть @safe_property
, также создает функцию-обертку, которая подходит в качестве получателяФункция, вы можете поместить ваш декоратор между строками @safe_property
и @property
, чтобы обернуть обертку, возвращенную предыдущую функцию:
@property
@my_decorator
@safe_property
def do_func(self):
print("inside do_func!")
return [2,3,4]
В любом случае, обертка вашего декоратора передается вызываемой для украшения, идолжен вернуть замену.Получатели свойств принимают только self
, ваша замена будет вызвана также self
, и никаких других аргументов:
def my_decorator(func):
def wrapper(self): # a replacement getter function, so only self is passed in
result = func(self) # call the original getter
if self.some_flag: # you can access the instance in the wrapper
# return only odd values from the getter
return [i for i in result if i % 2]
else:
# otherwise return the values unchanged
return result
return wrapper
Поместить @my_decorator
вверху означает украсить property()
объект,это не функция, поэтому вам нужно специально обрабатывать передачу такого объекта (вы можете увидеть, как @property
работает в ответе, который я написал до ).
Например, выможет извлечь получатель из атрибута property().fget
, а затем вернуть соответствующую замену (которая будет другим property()
объектом):
def my_decorator(prop):
getter = prop.fget
def wrapper(self): # a replacement getter function, so only self is passed in
result = getter(self) # call the original getter, taken from the property
if self.some_flag: # you can access the instance in the wrapper
# return only odd values from the getter
return [i for i in result if i % 2]
else:
# otherwise return the values unchanged
return result
# return a new property object, with the wrapper as the getter function
# and copying across all other property attributes
return property(wrapper, prop.fset, prop.fdel, prop.doc)
Обратите внимание, что свойство getter
функция будет только когда-либо передана self
, другие аргументы для методов получения свойств невозможны.
Однако обработка объекта property
напрямую не имеет никаких преимуществ перед размещением декоратора на одну строку ниже,это только усложняет ситуацию, добавляя ссылку prop.fget
и property(...)
возвращаемое значение.