Getters and setters in Python

February 6th, 2009 at 7:11 pm

I don’t like getters and setters. Besides being too wordly and often unnecessary, getters and setters make APIs less clean. Consider:

print dog.get_name()
dog.set_name('bozo')

Versus:

print dog.name
dog.name = 'bozo'

Isn’t the second one so much nicer and cleaner? No big difference? Then try to think of a complex class with dozens of attributes, is it fun writing brain-dead getters and setters for each?

Getters and setters belong to the sad world of Java and C++. This is because in those languages you have no choice. Suppose you just make a member public and let the class’s clients access it. What happens when you need to change the behavior of the member, or perhaps make it virtual (i.e. compute it on the fly from other members), or make something complex happen when it’s assigned? You then turn the member into a getter/setter pair and have a whole lot of code to rewrite. This is why in C++/Java, people use getters and setters from the start.

But in languages like Python it’s unnecessary! You can just begin with a plain attribute, letting clients access it. If, at some point, a need will arise to hide the attribute from direct access, no problem, just use the property function.

The canonical example is degrees and radians. Suppose you’ve been only using radians in your code, so Vector.angle was a simple attribute. But for some reason, you had to switch to degrees for the internal representation. What to do about the KLOCs of user code expecting angle to be just an attribute returning the angle in radians? No problem:

import math


class Vector(object):
    def __init__(self, angle_rad):
        self.set_angle_rad(angle_rad)

    def get_angle_rad(self):
        return math.radians(self._angle_deg)

    def set_angle_rad(self, angle_rad):
        self._angle_deg = math.degrees(angle_rad)

    angle = property(get_angle_rad, set_angle_rad)

    def get_angle_deg(self):
        return self._angle_deg

    def set_angle_deg(self, angle_deg):
        self._angle_deg = angle_deg

    angle_deg = property(get_angle_deg, set_angle_deg)


v = Vector(2*math.pi)
print v.angle
print v.angle_deg

v.angle = math.pi
print v.angle
print v.angle_deg

See how we’ve easily turned the angle attribute into a virtual entity accessible via getter and setter functions.

The point is, just use attributes, not getters and setters. If you ever need to change the code for some reason (this will happen much less often than you expect), you can always change the internals but still present the old API to client code.

Related posts:

  1. Writing a game in Python with Pygame. Part I
  2. The limit of sin(h)/h, or deriving the sine function
  3. Shared counter with Python’s multiprocessing
  4. solution to the “math confusion”

18 Responses to “Getters and setters in Python”

  1. ripper234No Gravatar Says:

    Assuming you put C# in the same “sad world”, in C# the syntax of setter/getter properties is identical to direct variable access.

    It’s very useful for encapsulation – even if I don’t ever intend to change the property, I don’t want the users of List class to change its Count property, ever – so I set its accessibility to private or protected.

  2. freetoNo Gravatar Says:

    ripper234:
    class Parrot(object):
    def __init__(self):
    self._voltage = 100000

    @property #implicit getter
    def voltage(self):
    """Get the current voltage."""
    return self._voltage

    In this example a user can’t change voltage, but they don’t have to know to use a getter to access it’s value.

  3. AlekNo Gravatar Says:

    Handy! As annoying as getters and setters are to type and see I use them to be able to set break points while debugging to find out who is setting the value to something crazy. I never liked _not_ using get/set because of that. This fixes both problems: I can add the get and set later as needed with a property when I want to debug, thanks!

  4. elibenNo Gravatar Says:

    Ron,

    I didn’t put C# in that list on purpose, because I vaguely recalled that it also has nice and special syntax for setters and getters that doesn’t require all the Java-ish overhead. Isn’t this so?

  5. TomNo Gravatar Says:

    One thing that kinda hurts Python is that it’s not currently possible to give a docstring to a field.

  6. elibenNo Gravatar Says:

    @Tom,

    The 4th argument to property is a doc-string. Did you mean something else?

  7. rgzNo Gravatar Says:

    Who are you writing for this is ancient stuff! You should take a look at the property metaclasses for python2.5 as well as property.setter and property.deleter decorators that come with python3.0 and python2.6.

  8. elibenNo Gravatar Says:

    @rgz,

    This is for Python 2.5, I’ve not switched to 2.6/3 yet.

    And I wasn’t aware of property metaclasses for 2.5, can you give an example/link?

  9. SurajNo Gravatar Says:

    http://www.python.org/doc/2.6/library/functions.html#property will give you an idea of what rgz was talking about.
    I suggest you follow up this article with one for using underlying mechanism used by python to implement properties (i.e. Python Descriptors http://docs.python.org/reference/datamodel.html#implementing-descriptors). All ORM code you see uses those under the covers. You can look at http://code.google.com/p/couchdb-python/source/browse/trunk/couchdb/schema.py for a moderate example.

  10. Joseph LiseeNo Gravatar Says:

    I think he is talking about Ian Bicking’s metaclass, its pretty nice to use:
    http://svn.colorstudy.com/home/ianb/recipes/class_property.py

  11. ripper234No Gravatar Says:

    Ah, I didn’t realize the omission of C# was deliberate.

    The syntax for accessing properties is 100% like the syntax for variable access.

    In C# 2, the syntax for declaring properties was something like:

    int _foo; // the variable
    int Foo
    {
    get { return _foo;}
    set { _foo = value;} // value is a reserved keyword
    }

    The getter and setter can have different accessibility (private/protected).

    Of course this is a trivial property, any custom logic could be written in the setter/getter. For making writing the trivials … trivial, C# introduced auto properties:

    int Foo {get; set;}

  12. elibenNo Gravatar Says:

    Ron,

    Thanks, I recalled it was something nice of the sort. Indeed, C# is far above Java in this respect. And in many others, actually. IMHO C# is the most dynamic of the non-dynamic languages out there, especially its latest incarnation (is it 3.0 or 3.5, I don’t remember).

  13. ripper234No Gravatar Says:

    Latest C# is 3.0, the .Net framework is 3.5.

  14. EduardoNo Gravatar Says:

    In Ruby, with one line you create getter and setter for a attribute named “attrx” :attr_accessor :attrx

    I do program in Python also, but in this point Ruby is far far better. And, yes, encapsulation is necessary, and the lack of getter and setter make awkward.

  15. Peter GerdesNo Gravatar Says:

    It’s important not to confuse the syntactic sugar of avoiding defining getX and setX for every attribute you wish to expose and python’s feature of allowing property access to be intercepted.

    While brevity, other things being equal, is preferable requiring explicit getter/setter methods is at worst a minor inconvenience. Indeed, it’s not even worth considering when choosing a language because it could be transparently managed by an apprioriate IDE. If you wanted you could code in Java and have a fancy IDE that displayed the standard getter/setter methods for X as just @pubproperty int X or whatever. Though some might argue that having to explicitly define getters and setters discourages provision of unnecessary interfaces, e.g., a setter for a variable you don’t mean to be user setable.

    Of course the ruby syntax for defining getters/setters in a brief statement is more elegant than some IDE overlay but ultimately ruby’s magicly defined getters/setters are semantically identical to the longwinded getter/setter methods in java or C++ (assuming you never allow properties to be set from outside the class). In each of these languages when bad practices are avoided attributes are accessed directly by methods on the class while (ignoring friends) access from outside the class is always just a method call.

    Python’s system differs semantically since even methods defined on the class will have their attribute access intercepted. Of course you can choose to refer to the real attribute in a method instead but being able to intercept standard attribute access in previously defined methods is a substantial semantic difference.

    Personally I feel they are all wrong. While not critical being able to intercept property access by methods defined in your superclass is desierable, e.g., so you can say add some refcounting optimization to an existing class. However, it is undesierable that intercepting method access to attributes and external access to attributes should be packaged together.

    Ideally all external access is through briefly defined getter/setter methods as in ruby and then attribute setting/getting should be possible to intercept, e.g., you could write an around method that wraps your superclass’s attempts to get/set that attribute. Indeed, since such a wrapper would be declared inside the inherited class such a feature could be added even in static languages (essentially treating attributes as redefinable macros).

  16. maheshNo Gravatar Says:

    I have tried given example, it worked well in 2.7 version whereas it didnt work in 3.2 version.. Is there any change in the 3.2 version of getter and setter or 3.2 doesnt support getter and setter methods. Can you please tell me.

  17. elibenNo Gravatar Says:

    mahesh,

    The property function exists in Python 3.x and works the same as in 2.x

    The error you see must have to do with the print statement, which became a function in 3.x

  18. kmonsoorNo Gravatar Says:

    thank you. now my concept of @property is working-clear.

    Not crystal clear though :D

Leave a Reply

To post code with preserved formatting, enclose it in `backticks` (even multiple lines)