<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Honest to a Segfault &#187; Object Orientation</title>
	<atom:link href="http://blog.cdleary.com/tag/object-orientation/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.cdleary.com</link>
	<description>__author__ = &#039;Chris Leary&#039;</description>
	<lastBuildDate>Sun, 05 Sep 2010 20:41:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Monstrous polymorphism and a Python post-import hook decorator</title>
		<link>http://blog.cdleary.com/2009/04/monstrous-polymorphism-and-a-python-post-import-hook-decorator/</link>
		<comments>http://blog.cdleary.com/2009/04/monstrous-polymorphism-and-a-python-post-import-hook-decorator/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 18:00:29 +0000</pubDate>
		<dc:creator>cdleary</dc:creator>
				<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Dynamism]]></category>
		<category><![CDATA[Object Orientation]]></category>
		<category><![CDATA[Polymorphism]]></category>
		<category><![CDATA[Reflection]]></category>

		<guid isPermaLink="false">http://blog.cdleary.com/?p=521</guid>
		<description><![CDATA[[...] This entry is a small walk-through for code to detect interface conformity by inspection, enumerate the classes in the environment, manipulate classes in place, and add an import hook to manipulate classes loaded from future modules. [...]]]></description>
			<content:encoded><![CDATA[<p>I queue up a few thousand things to do before I get on an airplane: synchronize two-thousand <a href='http://www.google.com/reader'>Google Reader</a> entries, load up a bunch of websites I&#8217;ve been meaning to read, and make sure for-fun projects are pulled from their most updated branches.</p>
<p>Then, once I get up in the air, I realize that <strong>I don&#8217;t really want to do 90% of those things crammed into a seat with no elbow room.</strong> I end up doing one or two. Along with reading <a href='http://steve.yegge.googlepages.com/when-polymorphism-fails'>Stevey&#8217;s Drunken Blog Rant: When Polymorphism Fails</a>, this entry is all the productivity I can claim. The <a href='http://bitbucket.org/cdleary/vaporwarning-monsters/'>full code repository for this entry</a> is online if you&#8217;d like to follow along.</p>
<h3>Polymorphism Recap</h3>
<p>The word &#8220;polymorphic&#8221; comes from Greek roots meaning &#8220;many shaped.&#8221; (Or they lied to me in school &#8212; one of those.) From a worldly perspective I can see this meaning two things:</p>
<ul>
<li>A single object can take on many shapes, or</li>
<li>Requirements for a general &#8220;shape&#8221; can be satisfied by different categories of objects.</li>
</ul>
<p>As it turns out, both of these concepts apply to the Object-Oriented programming, but the canonical meaning is the latter. <tt>[*]</tt> As Yegge says:</p>
<blockquote><p>If you have a bunch of similar objects [...], and they&#8217;re all supposed to respond differently to some situation, then you add a virtual method to them and implement it differently for each object.</p></blockquote>
<p>(If you don&#8217;t know what a virtual method is, <a href="http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming">the Wikipedia page</a> has an alternate explanation.)</p>
<h3>Yegge&#8217;s Example</h3>
<p>Yegge demonstrates that strictly adhering to the principles of polymorphism does not always produce the best design:</p>
<blockquote><p>
Let&#8217;s say you&#8217;ve got a big installed base of monsters. [...] Now let&#8217;s say one of your users wants to come in and write a little OpinionatedElf monster. [...] Let&#8217;s say the OpinionatedElf&#8217;s sole purpose in life is to proclaim whether it likes other monsters or not. It sits on your shoulder, and whenever you run into, say, an Orc, it screams bloodthirstily: &#8220;I hate Orcs!!! Aaaaaargh!!!&#8221; (This, incidentally, is how I feel about C++.)</p>
<p>The polymorphic approach to this problem is simple: go through every one of your 150 monsters and add a doesMrOpinionatedElfHateYou() method.
</p></blockquote>
<p>This is a great counterexample &#8212; it induces an instant recognition of absurdity.</p>
<p>He then touches on the fact that dynamic languages allow you to do neat things consistent with polymorphism due to the flexibility of the object structure (which is typically just a hash map from identifiers to arbitrary object values):</p>
<blockquote><p>
I guess if you could somehow enumerate all the classes in the system, and check if they derive from Monster, then you could do this whole thing in a few lines of code. In Ruby, I bet you can&#8230; but only for the already-loaded classes. It doesn&#8217;t work for classes still sitting on disk! You could solve that, but then there&#8217;s the network&#8230;
</p></blockquote>
<p>This is clearly impractical, but I figured there was some exploratory value to implementing this challenge in Python. This entry is a small walk-through for code to detect interface conformity by inspection, enumerate the classes in the environment, manipulate classes in place, and add an import hook to manipulate classes loaded from future modules.</p>
<h3>The Antagonist</h3>
<p>Double entendre intended. :-)</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> OpinionatedElf<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    is_liked_by_class_name = <span style="color: black;">&#123;</span>
        <span style="color: #483d8b;">'OpinionatedElf'</span>: <span style="color: #008000;">True</span>,
        <span style="color: #483d8b;">'Orc'</span>: <span style="color: #008000;">False</span>,
        <span style="color: #483d8b;">'Troll'</span>: <span style="color: #008000;">False</span><span style="color: black;">&#125;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, name<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">name</span> = name
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> be_scary<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;I'm small, ugly, and don't like the cut of your jib!&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> proclaim_penchance<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, other<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> IMonster.<span style="color: black;">is_conforming</span><span style="color: black;">&#40;</span>other<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;I can't even tell what that is!&quot;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span>
        is_liked = other.<span style="color: black;">is_liked_by_elf</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        class_name = other.__class__.__name__
        <span style="color: #ff7700;font-weight:bold;">if</span> is_liked <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;I'm not sure how I feel about %s&quot;</span> <span style="color: #66cc66;">%</span> class_name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span>
        emotion = <span style="color: #483d8b;">'love'</span> <span style="color: #ff7700;font-weight:bold;">if</span> is_liked <span style="color: #ff7700;font-weight:bold;">else</span> <span style="color: #483d8b;">'hate'</span>
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'I %s %s!!! Aaaaaargh!!!'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>emotion, other.__class__.__name__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<h3>Determining which Classes are Monsters</h3>
<p>First of all, Python doesn&#8217;t require (nor does it encourage) a rigid type hierarchy. Python&#8217;s all about the interfaces, which are often implicit. <strong>Step one is to create a way to recognize classes that implement the monster interface</strong>: <tt>[%]</tt></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> IMonster<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
    required_methods = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'be_scary'</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> be_scary<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span>
&nbsp;
    @<span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> is_conforming<span style="color: black;">&#40;</span>cls, <span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
        result = <span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: #008000;">callable</span><span style="color: black;">&#40;</span><span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span><span style="color: #008000;">object</span>, attr_name, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> attr_name <span style="color: #ff7700;font-weight:bold;">in</span> cls.<span style="color: black;">required_methods</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s conforms? %s'</span>, <span style="color: #008000;">object</span>, result<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> result
&nbsp;
<span style="color: #ff7700;font-weight:bold;">assert</span> IMonster.<span style="color: black;">is_conforming</span><span style="color: black;">&#40;</span>IMonster<span style="color: black;">&#41;</span></pre></div></div>

<p>This is a simple little class &#8212; there are better third party libraries to use if you want <a href="http://wiki.zope.org/Interfaces/FrontPage">real interface functionality</a> (i.e. more generic conformity testing and <a href="http://en.wikipedia.org/wiki/Design_by_contract#Description">Design By Contract</a>).</p>
<h3>Enumerating the Classes in the Environment</h3>
<p>All of the modules that have been loaded into the Python environment are placed into <a href='http://docs.python.org/library/sys.html#sys.modules'><tt>sys.modules</tt></a>. By inspecting each of these modules, we can manipulate the classes contained inside if they conform to our monster interface.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> name, module <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">sys</span>.<span style="color: black;">modules</span>.<span style="color: black;">iteritems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    extend_monsters<span style="color: black;">&#40;</span>module<span style="color: black;">&#41;</span></pre></div></div>

<p>The <tt>extend_monsters</tt> function is a bit nuanced because immutable modules also live in <tt>sys.modules</tt>. We skip those, along with abstract base classes, which have trouble with <tt>inspect.getmembers()</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> extend_monsters<span style="color: black;">&#40;</span>module, extension_tag=<span style="color: #483d8b;">'_opinionated_extended'</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Extend monsters in the module's top-level namespace to
    tell if they are liked by the :class:`OpinionatedElf`.
    and tag it with the :param:`extension_tag` as a flag name.
    Do not attempt to extend already-flagged modules.
    Do not clobber existing methods with the extension method name.
&nbsp;
    Warning: swallows exceptional cases where :param:`module`
        is builtin, frozen, or None.
    &quot;&quot;&quot;</span> 
    name = module.__name__ <span style="color: #ff7700;font-weight:bold;">if</span> module <span style="color: #ff7700;font-weight:bold;">else</span> <span style="color: #008000;">None</span>
    <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Instrumenting module %s'</span>, name<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> module <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #dc143c;">imp</span>.<span style="color: black;">is_builtin</span><span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #dc143c;">imp</span>.<span style="color: black;">is_frozen</span><span style="color: black;">&#40;</span>name<span style="color: black;">&#41;</span> \
            <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>module, extension_tag, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Skipping module: %s'</span>, name<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span>
    module._opinionated_instrumented = <span style="color: #008000;">True</span>
    classes = <span style="color: #dc143c;">inspect</span>.<span style="color: black;">getmembers</span><span style="color: black;">&#40;</span>module, <span style="color: #dc143c;">inspect</span>.<span style="color: black;">isclass</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> name, cls <span style="color: #ff7700;font-weight:bold;">in</span> classes:
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s: %s'</span>, name, cls<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            conforming = IMonster.<span style="color: black;">is_conforming</span><span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">AttributeError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'__abstractmethods__'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>e<span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;"># Abstract class.</span>
                <span style="color: #ff7700;font-weight:bold;">continue</span>
            <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> conforming:
            <span style="color: #ff7700;font-weight:bold;">continue</span>
        class_name = cls.__name__
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Instrumenting class %s'</span>, class_name<span style="color: black;">&#41;</span>
        attr_name = <span style="color: #483d8b;">'is_liked_by_elf'</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>cls, attr_name<span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;"># Don't clobber existing methods.</span>
            <span style="color: #dc143c;">logging</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Method already exists: %s'</span>, cls<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">continue</span>
        <span style="color: #dc143c;">logging</span>.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Setting %s on %s'</span>, attr_name, class_name<span style="color: black;">&#41;</span>
        <span style="color: #008000;">setattr</span><span style="color: black;">&#40;</span>cls, attr_name,
            <span style="color: #ff7700;font-weight:bold;">lambda</span> <span style="color: #008000;">self</span>: OpinionatedElf.<span style="color: black;">is_liked_by_class_name</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>
                <span style="color: #008000;">self</span>.__class__.__name__, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>If we were going to be thorough, we would recurse on the members of the class to see if the class scope was enclosing any more <tt>IMonster</tt> classes, but you&#8217;re never really going to find them all: if a module defines a monster class in a function-local scope, there&#8217;s no good way to get the local class statement and modify it through inspection.</p>
<p>In any case, we&#8217;re at the point where we can modify all monsters in the top-level namespace of already-loaded modules.  What about modules that we have yet to load?</p>
<h3>Post-import Hook</h3>
<p>There is no standard post-import hook (that I know of) in Python. <a href='http://www.python.org/dev/peps/pep-0369/'>PEP 369</a> looks promising, but I couldn&#8217;t find any record of additional work being done on it. The current import hooks, described in <a href='http://www.python.org/dev/peps/pep-0302/'>PEP 302</a>, are all pre-import hooks. As such, you have to <em>decorate</em> the <tt>__import__</tt> builtin, wrapping the original with your intended post-input functionality, like so: <tt>[^]</tt></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> import_decorator<span style="color: black;">&#40;</span>old_import, post_processor<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    :param old_import: The import function to decorate, most likely
        ``__builtin__.__import__``.
    :param post_processor: Function of the form
        `post_processor(module) -&gt; module`.
    :return: A new import function, most likely to be assigned to
        ``__builtin__.__import__``.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">assert</span> <span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: #008000;">callable</span><span style="color: black;">&#40;</span>fun<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> fun <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span>old_import, post_processor<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> new_import<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        module = old_import<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> post_processor<span style="color: black;">&#40;</span>module<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> new_import</pre></div></div>

<p>After which we can replace the old <tt>__import__</tt> with its decorated counterpart:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">__builtin__</span>.<span style="color: #008000;">__import__</span> = import_decorator<span style="color: black;">&#40;</span><span style="color: #dc143c;">__builtin__</span>.<span style="color: #008000;">__import__</span>,
    extend_monsters<span style="color: black;">&#41;</span></pre></div></div>

<h3>The Network</h3>
<p>Yegge brings up the issue of dynamically generated classes by mentioning network communications, calling to mind examples such as <a href="http://en.wikipedia.org/wiki/Java_remote_method_invocation">Java&#8217;s RMI</a> and <a href="http://en.wikipedia.org/wiki/CORBA">CORBA</a>. This is a scary place to go, even just conceptualizing. If metaclasses are used, I don&#8217;t see any difficulty in decorating <tt>__new__</tt> with the same kind of inspection we employed above; however, code generation presents potentially insurmountable problems.</p>
<p>Decorating <a href="http://docs.python.org/library/functions.html#eval">the <tt>eval</tt> family of functions</a> to modify new classes created seems <em>possible</em>, but it would be challenging and requires additional research on my part. <tt>exec</tt> is a keyword/statement, which I would think is a hopeless cause.</p>
<h3>Footnotes</h3>
<p><tt>[*]</tt> In accordance with the former, an object can implement many interfaces.<br />
<tt>[^]</tt> This function is actually a generic decorate-with-post-processing closure, but I added the references to import for more explicit documentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cdleary.com/2009/04/monstrous-polymorphism-and-a-python-post-import-hook-decorator/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
