Overriding properties in python Overriding properties in python python python

Overriding properties in python


The Python docs on the property decorator suggest the following idiom:

class C(object):    def __init__(self):        self._x = None    @property    def x(self):        return self._x    @x.setter    def x(self, value):        self._x = value    @x.deleter    def x(self):        del self._x

And then subclasses can override a single setter/getter like this:

class C2(C):    @C.x.getter    def x(self):        return self._x * -1

This is a little warty because overriding multiple methods seems to require you to do something like:

class C3(C):    @C.x.getter    def x(self):        return self._x * -1    # C3 now has an x property with a modified getter    # so modify its setter rather than C.x's setter.    @x.setter     def x(self, value):        self._x = value * 2

Of course at the point that you're overriding getter, setter, and deleter you can probably just redefine the property for C3.


I'm sure you've heard this before, but apply has been deprecated for eight years, since Python 2.3. Don't use it. Your use of locals() is also contrary to the Zen of Python -- explicit is better than implicit. If you really like the increased indentation, there is no need to create a throwaway object, just do

if True:    @property    def foo(self):        return self._foo    @foo.setter    def foo(self, val):        self._foo = val

Which doesn't abuse locals, use apply, require creation of an extra object, or need a line afterwards with foo = foo() making it harder to see the end of the block. It works just as well for your old-fashioned way of using property -- just do foo = property(fget, fset) as normal.

If you want to override a property in an arbitrary subclass, you can use a recipe like this.

If the subclass knows where the property was defined, just do:

class ATimesTwo(A):    @A.foo.setter    def foo(self, val):        self._foo = val * 2


The answer of stderr satisfies most use cases.

I'd like to add a solution for the case where you want to extend a getter, setter and/or deleter. Two ways to do this are:

1. Subclass property

First way to do this is by subclassing the builtin property and adding decorators that are versions of getter, setter and/or deleter that extend the current get, set and delete callbacks

Example for a property that supports appending methods to the set-functions:

class ExtendableProperty(property):    def append_setter(self, fset):        # Create a wrapper around the new fset that also calls the current fset        _old_fset = self.fset        def _appended_setter(obj, value):            _old_fset(obj, value)            fset(obj, value)        # Use that wrapper as setter instead of only the new fset        return self.setter(_appended_setter)

Usage is the same as for normal properties, only now it is possible to add methods to the property setters:

class A(object):    @ExtendableProperty    def prop(self):        return self._prop    @prop.setter    def prop(self, v):        self._prop = vclass B(A):    @A.prop.append_setter    def prop(self, v):        print('Set', v)
>>> a = A()>>> a.prop = 1>>> a.prop1>>> b = B()>>> b.prop = 1Set 1>>> b.prop1

2. Overwrite getter, setter and/or deleter

Use a normal property, overwrite the getter, setter or deleter and then add calls to the fget, fset or fdel in the property of the parent class.

Example for the type of property as in example 1:

class A(object):    @property    def prop(self):        return self._prop    @prop.setter    def prop(self, v):        self._prop = vclass B(A):    @A.prop.setter    def prop(self, v):        A.prop.fset(self, v)  # This is the call to the original set method        print('Set {}'.format(v))

I think the first option looks nicer because the call to the super property's fset is not necessary