A basic tenet of object oriented coding is encapsulation: expose the interface but hide the implementation.

Seductress that it is, Python makes it very tempting to violate this principle. Since all members of an object are public, it’s easy to access and modify them from outside. For example:

class Person: def __init__(self): self.age = None jeff = Person() jeff.age = 5 # maturity

Compare this with Java, where you can make a member private, and use “getters” and “setters”:

class Person { private int age; public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public static void main(String[] args) { Person jeff = new Person(); jeff.setAge(5); } }

The Java version has better encapsulation. If you decide later to change “age” to, say, a float, a string(!), or if you move it into another internally linked object, it’s no big deal. Just change the body of the getAge() and setAge() methods to do the typecasting or make the extra call, and you won’t need to change any other code. The implementation changes; the interface stays the same.

Of course, you could write getters and setters in Python, too, but you can’t enforce their use (data members are public, remember?). A better way is to do some magic using __getattr__ and __setattr__, although that could get messy, especially if you have a lot of names to intercept.

This has been bothering me for a while. Then I recently discovered the built-in function property(), which lets you rewrite the example above as follows:

class Person(object): def __init__(self): self._age = None def get_age(self): return self._age def set_age(self, value): self._age = value def del_age(self): del self._age age = property(get_age, set_age, del_age) jeff = Person() jeff.age = 5

Sweeeet. From the outside, nothing seems different: it still appears that you’re getting and setting age directly, just as before. But property() calls get_age and set_age transparently, giving you a layer that effectively provides encapsulation, even though you can’t tell from the outside. After all, that’s the whole point of encapsulation: you shouldn’t be able to tell from the outside.

In fact, this is actually better than how Java does it. A first version of Person might very well have age as a member which its users directly modify: this is intuitive and effortless, both conceptually and syntactically. Only later might you need to bring property() into the picture, as the object’s internals change or grow more complex. And that’s how it should be: more lines of code and more complexity only when you need it.

(Of course, you still can’t hide data members, but this still goes a long way towards better, though not complete, encapsulation.)

I can’t remember ever seeing property() mentioned anywhere in tutorials or introductory docs (it’s in the reference for built-in functions) That’s especially odd considering that one of Python’s strengths is its powerful object features. It would make sense to talk about this in the context of encapsulation. Plus I wonder how widespread the use of property() is in real world code.

Stuff like this is why I love Python.

Update: Some good comments over at reddit.