Search code examples
pythongetter-settermagic-methods

What will go wrong if I store the value for a python getter and setter in __dict__?


I am using python getters and setters, but I don't like using a dummy variable to store the value. For example, a simple getter and setter in python might be defined like so:

class Foo(object):

    def get_bar(self):
        print('getting bar')
        return self._bar

    def set_bar(self,variable):
        print('setting bar')
        self._bar = variable

    bar = property(get_bar,set_bar)

Which makes bar work like a normal everyday attribute, except that it executes a print statement every time someone sets or reads it:

>>> my_fave_foo = Foo()
>>> my_fave_foo.bar = 5
setting bar
>>> print(my_fave_foo.bar)
getting bar
5

Until, that is, future me decides to use introspection to look at the attributes of my favorite Foo:

>>> print(my_fave_foo.__dict__)
{'_bar': 5}

This bugged me, even though I know it wasn't really a big problem, so I did this instead -

class Foo(object):

    def get_bar(self):
        print('getting bar')
        return self.__dict__['bar']

    def set_bar(self,variable):
        print('setting bar')
        self.__dict__['bar'] = variable

    bar = property(get_bar,set_bar)

Which has the expected behavior

>>> my_fave_foo = Foo()
>>> my_fave_foo.bar = 5
setting bar
>>> my_fave_foo.bar
getting bar
5
>>> print(my_fave_foo.__dict__)
{'bar': 5}

My question is: why is this a bad idea? Other people, for example in response to this question:

What's the Pythonic way to use Getters and Setters?

Recommend the underscore convention. I get the feeling that there is something wrong with what I did, but I don't know what it is. So please tell me, What will go wrong with this?

I will quickly note that this is a toy example, in my actual code there is a real reason to be using getters and setters.


Solution

  • I am using python getters and setters, but I don't like using a dummy variable to store the value.

    Why not? The value has to live somewhere, and it is logically an instance variable. Python doesn't have public/private.

    Until, that is, future me decides to use introspection to look at the attributes of my favorite Foo:

    Don't do that then. We are all responsible users.

    so I [named the instance variable the same as the property]. why is this a bad idea?

    Now you're relying on the fact that the property takes precedence over the dictionary item in order to understand this code. If the dictionary item and the property have different names, then it will be obvious to the introspecting user that some special behavior will be invoked.

    What will go wrong with this?

    Your code is misleading and will confuse you the next time you look at it.

    If you like, you can use self.__bar for the internal state, which mangles the name to self._Foo__bar, which is a defense against clashes caused by subclasses. See The Python Tutorial / Private Variables.