2

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.

Britzel
  • 205
  • 3
  • 8
  • Have you tried @property decorator – TUNAPRO1234 Oct 23 '20 at 11:21
  • @Britzel, I followed your link to your earlier question. I'm still a bit confused about one thing -- Do you want `a` and `b` to be *instance* attributes or *class* attributes? Hope you're aware of the difference. – fountainhead Oct 24 '20 at 10:00
  • Hi @fountainhead ! When I asked this question I was not yet aware of the difference. Now I think I am: A class attribute changes the value of the variable in the class, i.e. in the blueprint to create instances. So every new instance would have the new value, while every old instance would keep the old value. A change of an instance attribute leaves the blueprint unchanged, but it only changes the value of the value of the specific instance. Correct? – Britzel Oct 24 '20 at 21:18
  • @fountainhead If so, then I think what I need is an instance attribute. I am not 100% sure yet, since I didn't yet get to test it in my actual code. What I posted here was, what I believed to be a minimal example which demonstrates what I need. But it remains to be seen back in the office on Monday. ; ) – Britzel Oct 24 '20 at 21:19

1 Answers1

2

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.

jottbe
  • 4,228
  • 1
  • 15
  • 31
  • Hi @jottbe, and thank you so much! This now does exactly what I need. Could you please help my understanding: I do not know this notation with the `@`. I tried to remove these lines, but then it wouldn't work, so it seems to be important. What do these mean/do? – Britzel Oct 23 '20 at 16:16
  • Oh, I found a good source which explains it. It is a special type of decorator. – Britzel Oct 23 '20 at 19:35
  • Hi, it's called decorator. Without it, you would just have one method `a` btw. because the line `def a(self, bool)` would just overwrite the definition `def a(self)`. – jottbe Oct 23 '20 at 20:06