There's no way to replace the decorator syntax for your setter method with exactly one line. That's because in this specific situation, the little detail of how applying the decorator manually differs from @decorator
syntax matters.
That difference is that with @decorator
syntax, the function to be decorated is never bound to a name before it's passed to the decorator. In your code, the x
name is already in use in our namespace, for the property object decorating the getter function. If we temporarily bind x
to the undecorated setter function, we'll lose access to that object, and we need it, since the decorator we want to apply is one of its attributes!
You can work around this by giving the setter function a different name:
class D:
def __init__(self):
self._x = 'Hi'
def x(self):
return self._x
x = property(x) # this is the previous x value, which we will eventually overwrite
def x_setter(self, value): # rename this function, so we don't clobber x quite yet
self._x = value
x = x.setter(x_setter) # then apply the decorator manually, overwriting x
# we might want to `del x_setter` here, to avoid cluttering the namespace
As my comments show, the previous x
value does eventually get overwritten, by our new property that wraps both the getter and setter methods. But we can't do it too soon, or we won't be able to access x.setter
using the old version of x
.
A more natural way to call property
manually with both getter and setter methods is to pass both of them (and maybe a deleter too) in a single property
call:
class D:
def __init__(self):
self._x = 'Hi'
def x_getter(self):
return self._x
def x_setter(self, value):
self._x = value
x = property(x_getter, x_setter) # wrap both getter and setter in one call