Python: How to automatically change an attribute of an instance depending on the boolean value of another attribute of the same instance?

Viewed 515

Say I have the class and an instance of it

class MyClass:
    a = False
    b = [0,1,2]

MCi = MyClass()

Obviously MCi.a gives False and MCi.b gives [0,1,2].

What I would like to have is that the value of MCi.b changes to [0,1,2,3,4,5] if I set MCi.a = True. And I want it to go back to [0,1,2] when I set back MCi.a = False.

In other words, MCi.a should dictate MCi.b, without having to set the latter attribute value from the outside.

How can I do that?

This question is very close to this one, which I asked earlier, but I did not phrase my question carefully enough, so the solution provided there is not actually what I need. The idea to use __setattr__() might be a good start though. But so far I failed.

1 Answers

In such a case I would use a method to set the boolean. So that you never set the boolean instance variable from outside directly, but call a method to change it. And in case you want to hide, that in fact a method is used, you can define it as a property. This would look like:

class MyClass:
    # prefix the instance variables with an underscore
    # as a convention to indicate they are private
    _a = False
    _b = [0,1,2]

    # define accessors
    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, bool):
        self._a= bool
        if bool is True:
            self._b= [0,1,2,3,4,5]
        else:
            self._b= [0,1,2]

    # define accessors
    @property
    def b(self):
        return self._b

Now we can test this:

o= MyClass()
print(f'{o._a}, {o._b}')
o.a=True
print(f'{o._a}, {o._b}')
o.a=False
print(f'{o._a}, {o._b}')
print(o.b)
o.b=[12,3]

This prints:

False, [0, 1, 2]
True, [0, 1, 2, 3, 4, 5]
False, [0, 1, 2]
[0, 1, 2]
Traceback (most recent call last):

  File "<ipython-input-14-1e243ad0d3ed>", line 8, in <module>
    o.b=[12,3]

AttributeError: can't set attribute

So you can see, that indeed the content of _b was changed, when a bool was assigned via o.a= and also, that you access the value of o._b by using the property o.b, but you can't set it via o.b=. This is just because I have not defined the setter. If you like to have one, you would have to define a function for it, just like in the setter of a.

If you define it this way, you should follow the convention, that you do not access the real instance variables _a and _b anywhere outside class MyClass in your code.

Related