{"id":35,"date":"2007-12-05T10:57:55","date_gmt":"2007-12-05T17:57:55","guid":{"rendered":"http:\/\/codefork.com\/blog\/index.php\/2007\/12\/05\/pimping-pythons-property\/"},"modified":"2007-12-06T10:34:07","modified_gmt":"2007-12-06T17:34:07","slug":"pimping-pythons-property","status":"publish","type":"post","link":"https:\/\/codefork.com\/blog\/index.php\/2007\/12\/05\/pimping-pythons-property\/","title":{"rendered":"Pimping Python&#8217;s property()"},"content":{"rendered":"<p>A basic tenet of object oriented coding is <a href=\"http:\/\/en.wikipedia.org\/wiki\/Object-oriented_programming#Fundamental_concepts\">encapsulation<\/a>: expose the interface but hide the implementation.<\/p>\n<p>Seductress that it is, Python makes it very tempting to violate this principle. Since all members of an object are public, it&#8217;s easy to access and modify them from outside. For example:<\/p>\n<pre>class Person:\r\n    def __init__(self):\r\n        self.age = None\r\njeff = Person()\r\njeff.age = 5 # maturity<\/pre>\n<p>Compare this with Java, where you can make a member private, and use &#8220;getters&#8221; and &#8220;setters&#8221;:<\/p>\n<pre>class Person {\r\n    private int age;\r\n    public int getAge() {\r\n        return this.age;\r\n    }\r\n    public void setAge(int age) {\r\n        this.age = age;\r\n    }\r\n    public static void main(String[] args) {\r\n        Person jeff = new Person();\r\n        jeff.setAge(5);\r\n    }\r\n}<\/pre>\n<p>The Java version has better encapsulation. If you decide later to change &#8220;age&#8221; to, say, a float, a string(!), or if you move it into another internally linked object, it&#8217;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&#8217;t need to change any other code. The implementation changes; the interface stays the same.<\/p>\n<p>Of course, you could write getters and setters in Python, too, but you can&#8217;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.<\/p>\n<p>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:<\/p>\n<pre>class Person(object):\r\n    def __init__(self):\r\n        self._age = None\r\n    def get_age(self):\r\n        return self._age\r\n    def set_age(self, value):\r\n        self._age = value\r\n    def del_age(self):\r\n        del self._age\r\n    age = property(get_age, set_age, del_age)\r\njeff = Person()\r\njeff.age = 5<\/pre>\n<p>Sweeeet. From the outside, nothing seems different: it still appears that you&#8217;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&#8217;t tell from the outside. After all, that&#8217;s the whole point of encapsulation: you <em>shouldn&#8217;t<\/em> be able to tell from the outside. <\/p>\n<p>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&#8217;s internals change or grow more complex. And that&#8217;s how it should be: more lines of code and more complexity <em>only<\/em> when you need it.<\/p>\n<p>(Of course, you still can&#8217;t hide data members, but this still goes a long way towards better, though not complete, encapsulation.)<\/p>\n<p>I can&#8217;t remember ever seeing property() mentioned anywhere in tutorials or introductory docs (it&#8217;s in the <a href=\"http:\/\/docs.python.org\/lib\/built-in-funcs.html\">reference for built-in functions<\/a>) That&#8217;s especially odd considering that one of Python&#8217;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.<\/p>\n<p>Stuff like this is why I love Python.<\/p>\n<p><strong>Update<\/strong>: Some good comments over at <a href=\"http:\/\/programming.reddit.com\/info\/62ae7\/comments\/\">reddit<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;s easy to access and modify them from outside. For example: class Person: def __init__(self): self.age = None &hellip; <a href=\"https:\/\/codefork.com\/blog\/index.php\/2007\/12\/05\/pimping-pythons-property\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Pimping Python&#8217;s property()&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-35","post","type-post","status-publish","format-standard","hentry","category-python"],"_links":{"self":[{"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/35","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=35"}],"version-history":[{"count":0,"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/35\/revisions"}],"wp:attachment":[{"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=35"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=35"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codefork.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=35"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}