Created
May 21, 2011 09:43
-
-
Save spranesh/984405 to your computer and use it in GitHub Desktop.
Dynamic Dispatch in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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