Skip to content
Advertisement

Using the @property decorator for interrelated attributes within a Python class

This question relates to using the @property decorator within a class in Python. I want to create a class with two public attributes (say a and b). I also want the class to have a further public attribute (say c) that is always equal to some calculation based on the other attributes within the class (say a + b = c). The attribute c needs to be publicly getable, but because of the dependency on a and b, I don’t really want it to be publicly getable if that’s possible.

The code block below won’t run because when self.a is set in line 3, a.setter is being called which raises an AttributeError because self.b in line 14 is not yet set.

Is using the @property decorator the correct thing to do in this circumstance?

What is the most Pythonic way to correctly set the attributes a, b and c during the initialisation method? Ideally without having to define the relationship between a, b and c in more than one place if this is possible (i.e. unlike in the code below where the relationship between a, b and c is defined on lines 13 and 22)?

Also, is it possible to enforce that the user is not able to set the value of c directly and what is the most Pythonic way of doing this?

class ExampleClass1:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, a):
        self._a = a
        self.c = self._a + self.b

    @property
    def b(self):
        return self._b

    @b.setter
    def b(self, b):
        self._b = b
        self.c = self._b + self.a

Advertisement

Answer

I think you’re approaching this the wrong way. If you need an attribute c that is always the sum of a and b, then it’s that attribute that needs to be a property:

@property
def c(self):
    return self.a + self.b

and you don’t need properties for a or b at all.

This also solves the problem of making it non-settable; if you don’t define a setter for c, it can’t be set directly.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement