I have subclassed the built-in property
class (call it SpecialProperty
) in order to add more fields to it:
class SpecialProperty(property):
extra_field_1 = None
extra_field_2 = None
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
super().__init__(fget, fset, fdel, doc)
def make_special_property(func):
prop = SerialisableProperty(fget=func)
return prop
and I am able to use it in the same fashion as the built-in property()
decorator:
@my_module.make_special_property
def get_my_property(self): return self._my_property
I now want to further specialise my SpecialProperty
instances populating one of the extra fields I have added to the class with an arbitrary value.
Is it possible, in Python, to write a decorator that will return a property with also accepting extra parameters?
I'd like to do it via the decorator because this is where and when the information is most relevant, however I'm finding myself stuck. I suspect this falls under the domain of decorators with arguments that have been well documented (Decorators with arguments? (Stack Overflow), or Python Decorators II: Decorator Arguments (artima.com) to only cite a couple sources), however I find myself unable to apply the same pattern to my case.
Here's how I'm trying to write it:
@my_module.make_special_property("example string")
def get_my_property(self): return self._my_property
And on the class declaring get_my_property
:
>>> DeclaringClass.my_property
<SpecialProperty object at 0x...>
>>> DeclaringClass.my_property.extra_field_1
'example string'
Since I am making properties
, the decorated class member should be swapped with an instance of SpecialProperty
, and hence should not be a callable anymore -- thus, I am unable to apply the "nested wrapper" pattern for allowing a decorator with arguments.
Non working example:
def make_special_property(custom_arg_1):
def wrapper(func):
prop = SerialisableProperty(fget=func)
prop.extra_field_1 = custom_arg_1
return prop
return wrapper # this returns a callable (function)
I shouldn't have a callable be returned here, if I want a property I should have a SpecialProperty
instance be returned, but I can't call return wrapper(func)
for obvious reasons.
Your decorator doesn't return a callable. Your decorator factory returns a decorator, which returns a property. You might understand better if you rename the functions:
def make_decorator(custom_arg_1):
def decorator(func):
prop = SerialisableProperty(fget=func)
prop.extra_field_1 = custom_arg_1
return prop
return decorator
When you decorate with make_decorator
, it is called with an argument, and decorator
is returned and called on the decorated function.