Skip to content

Instantly share code, notes, and snippets.

@spranesh
Created May 21, 2011 09:43
Show Gist options
  • Save spranesh/984405 to your computer and use it in GitHub Desktop.
Save spranesh/984405 to your computer and use it in GitHub Desktop.
Dynamic Dispatch in Python
def Analyse(obj):
""" Dynamic Dispatch based on object's class type.
This will call the AnalyseClassName
Example: if obj is of type Let, then call AnalyseLet,
if it is of type IfElse call AnalyseIfElse
"""
# Get obj's class name
class_name = obj.__class__.__name__
# Create the function name as a string
function_name = 'Analyse'+class_name
# Call the AnalyseName method
try:
# globals is a dictionary of all the symbols seen so far.
globals_vars = globals()
function = global_vars[function_name]
return function(obj)
except KeyError, e:
raise NotImplementedError("%s function is not implemented."%function_name)
# We can now implement functions like
def AnalyseConstant(obj):
pass
def AnalyseIfElse(obj):
# Do Something here
# ..
# Maybe call Analyse on the children
map(Analyse, obj.children)
#########################################################################
# The basic idea in what we did was dynmically construct the function name to
# be called, and acess it from the globals() dictionary.
#
# The above should work but the ONLY problem is that accessing the globals
# dictionary as we did in Analyse is rather slow. In fact it is one of the
# slowest operations in Python. Python internally represents the variables
# seen in some other format. And when we call globals(), it CONSTRUCTS a
# dictionary for us, at runtime. We cannot have this overhead for each
# dispatch.
#
# The way we get around this is by creating a local namespace. The easiest way
# to do this is a class. Then we can call the getattr function on self, with a
# string, to get the value represented by the string. That is, if there was a
# method AnalyseIfElse in a class, we could do:
#
# analyse_if_else_function = getattr(self, 'AnalyseIfElse')
#
# to get the AnalyseIfElse function in the analyse_if_else_function variable.
# Using getattr is MUCH faster.
#
# So we write it as follows:
#########################################################################
class Analyser:
def Analyse(self, obj):
# same stuff as before
class_name = obj.__class__.__name__
function_name = 'Analyse'+class_name
try:
# Instead of using global_vars, we use getattr
function = getattr(self, function_name)
return function(obj)
except KeyError, e:
raise NotImplementedError("%s method is not implemented."%function_name)
# Now we can define Methods as follows:
def AnalyseConstant(self, obj):
pass
def AnalyseIfElse(self, obj):
# Do some stuff
# Call Analyse on the children.
# Note the 'self'.Analyse
map(self.Analyse, obj.children)
# etc..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment