Python property setter in subclass

I have a SuperClass which defines a property and it's setter, like so:

class A[object]:
    def __init__[self]:
        self._mode = None

    @property
    def mode[self]:
        # to be overriden in subclass to implement the actual getter code
        raise NotImplementedError

    @mode.setter
    def mode[self, value]:
        # common assertions and input validations
        self._set_mode[value]

    def _set_mode[self, value]:
        # to be overriden in subclass to implement the actual setter code
        raise NotImplementedError


class B[A]:
    @property
    def mode[self]:
        return self._mode

    def _set_mode[self, value]:
        self._mode = value


obj = B[]
obj.mode = 'test'

Which raises

obj.mode = 'test'
AttributeError: can't set attribute

It would seem that I have to register a setter in B. I'd usually do this like @A.mode.setter, but that doesn't quite apply here as I don't actually want to define a new setter in B, just re-use the one from A.
Does anyone have a hint on how to solve this? Might be trivial, but I'm not seeing it right now :/

asked Mar 13, 2017 at 12:07

1

the getter and setter are stored as attributes of the property object [respectively as .fget and .fset], so as soon as you overload the property in a child class you most explicitely provide both getter and setters, ie:

class B[A]:
    @property
    def mode[self]:
        return self._mode

    @mode.setter
    def mode[self, value]:
        self._mode = value

So if you want to make the getter and/or setter overloadable without having to redeclare the property, you have to define a _get_mode method and make your property's getter delegate to this method, just like you did for the setter.

class A[object]:
    def __init__[self]:
        self._mode = None

    @property
    def mode[self]:
        return self._get_mode[]

    def _get_mode[self]:
        # to be overriden in subclass to implement the actual getter code
        raise NotImplementedError

    @mode.setter
    def mode[self, value]:
        # common assertions and input validations
        self._set_mode[value]

    def _set_mode[self, value]:
        # to be overriden in subclass to implement the actual setter code
        raise NotImplementedError


class B[A]:

    def _get_mode[self]:
        return self._mode

    def _set_mode[self, value]:
        self._mode = value

answered Mar 13, 2017 at 12:22

Analogously with using mode.setter inside A’s definition, this answer to a related question suggests to use a property of a base class to define a property on a subclass like so:

class B[A]:
    @A.mode.getter              # only this line is changed!
    def mode[self]:
        return self._mode

    def _set_mode[self, value]:
        self._mode = value

Here, mode.setter will be the same as it was for A, but we’ve replaced the getter.

answered Mar 2, 2021 at 22:02

arseniivarseniiv

982 silver badges7 bronze badges

It works for me this way

class A:
    @property
    def mode[self]:
        raise NotImplemented
    
    @mode.setter
    def mode[self, value]:
        raise NotImplemented

class B[A]:
    @A.mode.setter
    def mode[self, value]:
        # your setter implement here

answered Aug 1, 2021 at 17:41

ganiularganiular

1531 silver badge7 bronze badges

Python @property inheritance the right way

Given a Parent class with value property, Child can inherit and overload the property while accessing Parent property getter and setter.

Although we could just reimplement the Child.value property logic completely without using Parent.value whatsover, this would violate the DRY principle and, more important, it wouldn't allow for proper multiple inheritance [as show in the example property_inheritance.py bellow].

Two options:

  • Child redefines value property completely, both getter and setter.

  • Child uses Parent.value property, and only overloads setter. Parent class must be referenced explicitly.

In either pattern, using Parent.value.getter is as simple as

However, accessing Parent.property.setter is more verbose:

super[Child, type[self]].value.fset[self, new_value]

It would be nice to just super[].value = new_value but this won't work due to super current implementation [as Python 3.7]. There is a Python Issue regarding this rather unintuitive behaviour.

Are properties inherited in Python?

Inheritance allows us to define a class that inherits all the methods and properties from another class. Parent class is the class being inherited from, also called base class.

Is @property a getter?

@property is used to get the value of a private attribute without using any getter methods. We have to put a line @property in front of the method where we return the private variable. To set the value of the private variable, we use @method_name.

Should you use setters and getters in Python?

Getters and Setters in python are often used when: We use getters & setters to add validation logic around getting and setting a value. To avoid direct access of a class field i.e. private variables cannot be accessed directly or modified by external user.

Chủ Đề