Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access superclass' 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 :/

like image 387
Emanuel Ey Avatar asked Mar 13 '17 12:03

Emanuel Ey


People also ask

When to use python@ property?

Python's property() is the Pythonic way to avoid formal getter and setter methods in your code. This function allows you to turn class attributes into properties or managed attributes. Since property() is a built-in function, you can use it without importing anything.

Are getters and setters inherited Java?

Do the setter/getter methods always affect only values in objects where they are declared, even called from a subclass by inheritance? You cannot inherit the methods but not the variables. You inherit everything from the parent class. Private just means that you cannot directly access it, but it is still there.

What is@ property Python class?

Python property() function returns the object of the property class and it is used to create property of a class. Syntax: property(fget, fset, fdel, doc) Parameters: fget() – used to get the value of attribute. fset() – used to set the value of attribute.

Are getters and setters properties?

Accessor properties are represented by “getter” and “setter” methods. In an object literal they are denoted by get and set : let obj = { get propName() { // getter, the code executed on getting obj. propName }, set propName(value) { // setter, the code executed on setting obj.


2 Answers

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
like image 157
bruno desthuilliers Avatar answered Nov 20 '22 19:11

bruno desthuilliers


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.

like image 29
arseniiv Avatar answered Nov 20 '22 18:11

arseniiv