Dynamic method binding with inheritance in Python
<p>I am new to python (~ a month), and I wish I had switched to it sooner (after years of perl). </p>

<p><strong>Problem</strong>:  I want objects to have different functionality to the same method call based on their type. The methods are assigned at runtime, based on the module loaded (which composes all objects).</p>

<p><strong>Question</strong>: I wanted to know if there was a popular design pattern that I could use instead of the below, or if this already has a design pattern name (I sadly have no formal CS background, and knowing this will help my documentation)<strong>?</strong></p>

<p>I have a class hierarchy (as of now, 26 of them with 3 base classes). Only the base classes have some trivial methods (eg: add_child), and each derived class only extends the base class with new data attributes (specific to the derived class), overriding methods when necessary (eg: __str__).</p>

<p>I am dealing with tree(s) where nodes are of different classes. Yet, the nodes should the same certain method names (<code>stringify</code>, <code>print_tree</code>, <code>emit</code>, <code>eval</code>, <code>transform_X</code>, etc), thereby allowing easy/blind iterator operation. Each method may do something different, yet the methods have the same call name (like <em>polymorphism</em>).</p>

<p>I primarily wanted to grant specific abilities (methods) to nodes, based on their type. Initially, I implemented this using the <a href="http://stackoverflow.com/questions/25891637/visitor-pattern-in-python?newreg=d5c745988c5844e8a248268074a9b7bb">Visitor Pattern</a>. But, then realized I didn't really have to, considering I was working in Python.</p>

<p>In the below example, I have methods which are dynamically assigned to classes. Note, in below example the iteration/recursion method call name (<code>print_tree</code>) is different from the function name (<code>generic__print_tree</code>).</p>

<pre class="lang-py prettyprint-override"><code>#astmethods.py
def generic__print_tree(self, level=1):
    """
    Desc: print nodes with indentation
    Target: Any tree node
    """
    print("{}&gt; {}".format('-' * level, self))
    for child in self.children:
            child.print_tree((level + 1))


def ASTNode__stringify(self):
    """
    Desc: Return string representation of the tree under this node
    Target: AST/CFG nodes
    """
    text = str(self)
    for child in self.children:
            text += ", { " + child.stringify() + " }"
    return text
</code></pre>

<p>Finally the <strong>main</strong> modules has this function, <em>extend_types()</em> which gets called during module init. The nodes are expected to do different things, within the context of this module, based on their type (not value). The methods assigned are inherited, unless overridden.</p>

<pre class="lang-py prettyprint-override"><code># mainModule1.py
def extend_types():
    """
    Upgrade the AST node classes with neat functions for use within this module's context
    """
    # same simple functions across class hierarchies
    # I should just derive them both from a common base class to avoid this
    ASTNode.print_tree = generic__print_tree
    SimpleNode.print_tree = generic__print_tree

    # ASTNode and all derived class get this method
    ASTNode.stringify = ASTNode__stringify

    # All AST nodes get the base method, except for Ignore and Arraysel type nodes
    # traversal looks the same with child.tidy()
    ASTNode.tidy = ASTNode__tidy
    ASTIgnore.tidy = ASTIgnore__tidy
    ASTArraySel.tidy = ASTArraySel__tidy

    # All AST nodes get the base method, except for the Coverage and If type nodes
    ASTNode.transform_controlFlow = ASTNode__transform_controlFlow
    ASTCoverage.transform_controlFlow = ASTCoverage__transform_controlFlow
    ASTIf.transform_controlFlow = ASTIf__transform_controlFlow
</code></pre>

<p>edit: removed distracting info, made the example for a single module context</p>

<h2>Problem Summary</h2>

<p>Ignoring the irrelevant details, the problems here can be summed up as follows:</p>

<p>There is one base class and many derived classes. There is a certain functionality which should apply to all of the derived classes, but depends on some external switch (in the question: choice of <em>"<strong>main</strong> module"</em>).</p>

<p>The idea in the question is to monkeypatch the base class depending on the switch. </p>

<h2>Solution</h2>

<p>Instead of that, the functionality which depends on the external switch should be separated.</p>

<p>In example:</p>

<pre><code># There is a base class:

class ASTNode(object):
    pass


# There are many derived classes, e.g.:


class ASTVar(ASTNode):
    pass


# One implementation of function stringify or another
# should be defined for all objects, depending on some external factor


def stringify1(node):
    # something


def stringify2(node):
    # something else


# Depending on whatever, choose one of them:

stringify = stringify1
</code></pre>

<p>This is now used just a little bit differently than in the original code: intead of <code>node.stringify()</code>, there is now <code>stringify(node)</code>. But there is nothing wrong with that.</p>

<p>BTW...</p>

<p>Maybe it would be more pleasing to the eye to use a class:</p>

<p>class NodeHandler1(object):
    def print_tree(node):
        # do something</p>

<pre><code>def stringify(node):
    # do something

...
</code></pre>

<p>But that is not required at all.</p>

<h2>The Moral</h2>

<p>Do not monkeypatch. That is always bad design.</p>

python design-patterns visitor