<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[Important Shock]]></provider_name><provider_url><![CDATA[https://importantshock.wordpress.com]]></provider_url><author_name><![CDATA[Patrick Thomson]]></author_name><author_url><![CDATA[https://importantshock.wordpress.com/author/importantshock/]]></author_url><title><![CDATA[Adventures in Pythonic&nbsp;Encapsulation]]></title><type><![CDATA[link]]></type><html><![CDATA[<p>Python has undergone a fair share of criticism for its lack of support for <a href="http://en.wikipedia.org/wiki/Information_hiding" target="_blank">information hiding</a>. Despite its being a solidly object-oriented language, Python has historically refused to support this facet of object-orientation. Other programming languages have implemented encapsulation in a variety of ways:</p>
<ul>
<li>All variables in Smalltalk, the canonical OO language, are private; in order to access them, the programmer must write explicit accessor and mutator methods for each variable.</li>
<li> C++, Java, and C# rely on the <code>public</code>,<code> private</code>, and <code>protected</code> keywords in order to implement variable scoping and encapsulation.</li>
<li>Cocoa&#8217;s Objective-C code strongly encourages the programmer to use <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/BasicPrinciples.html">key-value coding</a> for encapsulatory purposes.</li>
<li>Ruby does ultra-sexy encapsulation through the <code>attr_accessor</code> function(s).</li>
</ul>
<p>However, Pythonistas like myself often assert that &#8220;<a href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/dad0361902521632/ed40457da2dc10b2?lnk=st&amp;q=%22we%27re+all+consenting+adults+here%22+python&amp;rnum=2&amp;hl=en#ed40457da2dc10b2">we&#8217;re all consenting adults here</a>.&#8221; While this attitude is refreshing in this day of slavish devotion to OOP principles, the Python community has realized that in order to avoid alienating newcomers, Python should perform some sort of encapsulatory behavior. This article intends to show the various ways in which Python supports encapsulation and/or information hiding.</p>
<p><!--more-->For the sake of argument, let&#8217;s implement a <code>Student</code> class:</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">class Student(object):

</span>    <span class="meta meta_paragraph meta_paragraph_text">def __init__(self, name):

</span>        <span class="meta meta_paragraph meta_paragraph_text">self.name = name</span></span></pre>
<p>Easy enough, right? Now, let&#8217;s write a unit test. <strong>Note that it depends on the <code>name</code> attribute being stored as a string.</strong></p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">george = Student("George Washington")

print george.name.lower()</span></span></pre>
<p>When run, this test will produce the following output: <code>george washington</code><br />
But what if *cue dramatic music* we changed the implementation of the Student class so that it stored the <code>name</code> variable as a list of strings?</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">class Student(object):

</span>    <span class="meta meta_paragraph meta_paragraph_text">def __init__(self, name):

</span>        <span class="meta meta_paragraph meta_paragraph_text">self.name = name.split()</span></span></pre>
<p>Now, running the above unit test will give us the following error:<br />
<code>AttributeError: 'list' object has no attribute 'lower'</code><br />
So how could we modify the Student class in such a way that people could interact with it as a string, despite it being stored in a list? Read on.<br />
<!--more--><br />
Method 1: <strong>Getters and setters</strong><br />
Python, being an underscore-happy language (not that there&#8217;s anything wrong with that!) allows for automatic variable-name-mangling with the addition of two preceding underscores; that is a fancy way to say that, in a Student class, a variable named <code>__name</code> will actually have the variable name <code>_Student_name</code> at runtime. Therefore, we could write the following code, using getters and setters (I&#8217;m using the Smalltalk-style naming conventions &#8211; <code>foo</code> accesses the variable <code>foo</code>, and <code>setFoo</code> sets it &#8211; for getters and setters here, though it applies equally well to Java&#8217;s <code>getFoo</code> and <code>setFoo</code> paradigm), and thereby encapsulate details of the class variables inside the class:</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">class Student(object):

</span>

    <span class="meta meta_paragraph meta_paragraph_text">def __init__(self, name):

</span>        <span class="meta meta_paragraph meta_paragraph_text">self.__name = name.split()

</span>

    <span class="meta meta_paragraph meta_paragraph_text">def name(self):

</span>        <span class="meta meta_paragraph meta_paragraph_text">return " ".join(self.__name)

</span>

    <span class="meta meta_paragraph meta_paragraph_text">def setName(self, newName):

</span>        <span class="meta meta_paragraph meta_paragraph_text">self.__name = newName.split()</span></span></pre>
<p>However, in order to get the unit test to work, we need to change it to this:</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">george = Student("George Washington")

print george.name().title()</span></span></pre>
<p>After that, everything works dandily.</p>
<p><strong>Advantages of this method:</strong></p>
<ul>
<li>It follows other languages&#8217; paradigms for accessor methods</li>
<li>It doesn&#8217;t require much effort to implement</li>
</ul>
<p><strong>Disadvantages of this method:</strong></p>
<ul>
<li>The end-user must change his/her programs to use accessor methods.</li>
<li>It can be unclear whether one&#8217;s using the Java or Smalltalk accessor paradigm.</li>
<li>The end user can access the internal object &#8211; in this case, by using <code>_Student_name</code></li>
</ul>
<p><!--more--><br />
Method 2: <strong>__getattr__ and __setattr__</strong></p>
<p>By overloading the __getattr__ and __setattr__ methods, one can intercept all calls to read or assign the value of an attribute belonging to a class. Using this, plus the double-underscore name-mangling paradigm, you can insert true, 100% garden-fresh private members. Here&#8217;s an example &#8211; it&#8217;s best written, not explained.</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">class Student(object):
</span>
    <span class="meta meta_paragraph meta_paragraph_text">def __init__(self, name):
</span>        <span class="meta meta_paragraph meta_paragraph_text">self.name = name
</span>
    <span class="meta meta_paragraph meta_paragraph_text">def __getattribute__(self, attr):
</span>        <span class="meta meta_paragraph meta_paragraph_text">if attr == "name":
</span>            <span class="meta meta_paragraph meta_paragraph_text">return " ".join(self.__dict__[attr])
</span>        <span class="meta meta_paragraph meta_paragraph_text">else:
</span>            <span class="meta meta_paragraph meta_paragraph_text">return object.__getattribute__(self, attr)
</span>
    <span class="meta meta_paragraph meta_paragraph_text">def __setattr__(self, attr, value):
</span>        <span class="meta meta_paragraph meta_paragraph_text">if attr == "name":
</span>            <span class="meta meta_paragraph meta_paragraph_text">self.__dict__[attr] = value.split()
</span>        <span class="meta meta_paragraph meta_paragraph_text">else:
</span>            <span class="meta meta_paragraph meta_paragraph_text">object.__setattr__(self, attr, value)</span></span></pre>
<p><strong>Advantages of this method:</strong></p>
<ul>
<li>Transparent encapsulation; __setattr__ and __getattr__ are called even when it appears that the user is modifying an instance variable through the assignment operator.</li>
</ul>
<p><strong>Disadvantages of this method:</strong></p>
<ul>
<li>Verbose.</li>
<li>Complicated to implement.</li>
<li>Prone to errors.</li>
</ul>
<p><!--more--><br />
Method 3: <strong>properties</strong></p>
<p>Python 2.2 implemented a new style of attribute access, called <strong>properties</strong>. Simply put, they&#8217;re faster, easier ways to implement the __getattr__ and __setattr__ methods&#8217; ways of transparent attribute gathering. Here&#8217;s an example:</p>
<pre><span class="text text_plain"><span class="meta meta_paragraph meta_paragraph_text">class Student(object):
</span>    <span class="meta meta_paragraph meta_paragraph_text">def __init__(self, name):
</span>        <span class="meta meta_paragraph meta_paragraph_text">self.__name = name
</span>
    <span class="meta meta_paragraph meta_paragraph_text">def getName(self):
</span>        <span class="meta meta_paragraph meta_paragraph_text">return " ".join(self.__name)
</span>
    <span class="meta meta_paragraph meta_paragraph_text">def setName(self, newName):
</span>        <span class="meta meta_paragraph meta_paragraph_text">self.__name = newName.split()
</span>
    <span class="meta meta_paragraph meta_paragraph_text">name = property(getName, setName)</span></span></pre>
<p>Now, all assignment references to the name attribute will return properly. And, since we defined getName and setName, programmers who are used to the accessor-method paradigm can use those.</p>
<p><strong>Advantages of this method</strong>:</p>
<ul>
<li>Transparent encapsulation</li>
<li>Very elegant</li>
<li>Allows for multiple paradigms of accessing values.</li>
</ul>
<p><strong>Disadvantages of this method</strong>:</p>
<ul>
<li>Very verbose &#8211; however, using lambda statements makes things a bit clearer, and <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157768">this</a> crazy-awesome code allows for automated property generation. (Psst! Guido! If you want your language to be flocked to like Ruby, allow for metaprogramming like this! Incorporate this into the Python code base! At the very least, give us some ways to make syntactic sugar, like Ruby&#8217;s class_eval and instance_eval.</li>
<li>Determined people can still access the internal object &#8211; however, is this truly a disadvantage? There are times when it&#8217;s useful to break encapsulation, such as running a proper debugger.</li>
</ul>
<p><!--more--><br />
In conclusion:</p>
<p>These days, I&#8217;m using properties. They seem to be the best way to implement encapsulatory principles &#8211; and if the <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157768">attribute</a> methods get incorporated into the Python built-in object class, I shall never pine for Ruby&#8217;s attr_accessor again. And that&#8217;s a good thing, because I truly want Python to succeed.</p>
<p>Any inaccuracies? Complaints? Death threats? Compliments? Leave a comment!</p>
]]></html></oembed>