0

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.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • 1
    can't you use simply `self.bar` without all this getter/setter ? – furas Jan 21 '17 at 00:02
  • 2
    I wouldn't exactly call mutating the class in a constructor a "simple" example… – Josh Lee Jan 21 '17 at 00:05
  • Your indentation is off a bit... are you doing the `setattr` inside the `__init__`? Typically this is done once at the class level and not per-instance. – tdelaney Jan 21 '17 at 00:25
  • Add prints to your getter and setter. You'll see that once you do `my_fave_boo.bar = 5`, the instance namespace now has a local variable called `bar` referencing an integer and the getters and setters aren't called any more. – tdelaney Jan 21 '17 at 00:33
  • @tdelaney, I was doing it inside `__init__` - changing to the syntax to `bar = property(...,...)` outside of `__init__` seems to be the correct method? – Abe Levitan Jan 21 '17 at 00:43
  • I tried adding print statements too, and they continued to be called each time I got or set the variable. – Abe Levitan Jan 21 '17 at 00:44
  • Pull the getters / setters back to the class level and also at the class level do `boo = property(get_bar, set_bar)`. When the class is first defined, you are in the class namespace already. – tdelaney Jan 21 '17 at 00:53
  • As for the prints, I must have messed up my test code.... it does work. – tdelaney Jan 21 '17 at 01:05
  • Regarding the `print`s - I'm experiencing different behaviour in Python2 and 3. Could somebody please confirm? – VPfB Jan 21 '17 at 12:43
  • I have added print statements to the question for clarity, and , and @VPfB, in python 2 apparently new-style classes are required for getters and setters, so now print behavior is the same between python 2 and 3. The original question (what is wrong with the second pattern) still remains – Abe Levitan Jan 22 '17 at 04:04
  • this is in fact how `@cached_property` is usually implemented: https://github.com/pydanny/cached-property/blob/d4d48d2b3415c0d8f60936284109729dcbd406e6/cached_property.py#L12-L27 – anthony sottile Jan 22 '17 at 04:08

1 Answers1

0

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.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275