What's the problem?python
Assuming that you have some well written library which parses a file and invokes callbacks when some certain pattern's encountered (For example, SAX).ide
The most common way to make use of its utility is to inherit from it, override the callbacks and do your own stuff.this
Here's a small piece of code demonstrating this method:spa
import re, sys class Substantial: regexp_callback = re.compile(r'<([^<>]+)>') def callback(self, name=None): print 'Substantial callback' def parse(self, string): m = self.regexp_callback.match(string) if m: self.callback(m.group(1)) class MyHandler(Substantial): def callback(self, name=None): print 'MyHandler callback' # we're likely to have a long-long if-else statement here # without mixin class
As the code comment states, WE ARE LIKELY TO HAVE A LONG IF-ELSE STATEMENT IN CALLBACKS.scala
Assuming the input file has contents like:code
<callback1>regexp
<hello>xml
<nice>ip
...ci
It's probable that we've got to write code in callbacks like this:
if content-in-angle-brackets == 'callback1': XXXX
elif content-in-angle-brackets == 'hello': XXXX
.....
This is not scalable and difficult to maintain!
How do we solve this problem, i.e, avoid the long if-else statement to make the project more maintainable?
First Solution to Avoid Long If-Else problem
The first solution may be obvious. Most of us may code like this:
class MyHandler(Substantial): def callback(self, name=None): # we're likely to have a long-long if-else statement here # without mixin class if name.upper() == 'CALLBACK1': self.doCALLBACK1() elif name.upper() == 'CALLBACK2': self.doCALLBACK2() elif name.upper() == 'CALLBACK3': self.doCALLBACK3() # actual callbacks def doCALLBACK1(self): print 'MyHandler: doCALLBACK1' def doCALLBACK2(self): print 'MyHandler: doCALLBACK2' def doCALLBACK3(self): print 'MyHandler: doCALLBACK3'
def parseFile(filename, handler): with open(filename, "r") as f: for line in f: handler.parse(line.strip())
Well, this is acceptable, but the long if-else problem's still there. If We're going to define 10 callbacks, we're forced to write 10 if-elif statements. Isn't there any better way? Say, we just write a small piece of code, and this code takes care of dispatching methods, and the only thing we should focus on is to write well-defined callbacks.
A Better Solution: mix-in class (used as a dispatcher and helper)
The solution is that by introducing a mix-in class, we delegate the dispatching task to the mix-in class and only focus on actual callback functions.
The code is like this.
class Mixin: def callback(self, name=None): if name: mname = 'do'+name.upper() method = getattr(self, mname, None) if callable(method): method() class MyHandler2(Mixin, Substantial): # actual callbacks def doCALLBACK1(self): print 'MyHandler2: doCALLBACK1' def doCALLBACK2(self): print 'MyHandler2: doCALLBACK2' def doCALLBACK3(self): print 'MyHandler2: doCALLBACK3'
Demo
if __name__ == '__main__': if len(sys.argv) < 2: print 'argument error, please specify an input file' else: print '=======Substantial================' parseFile(sys.argv[1], Substantial()) print '=======MyHandler(Directly inherit from Substantial==========' parseFile(sys.argv[1], MyHandler()) print '=======MyHandler2 (Inherit from Mixin and Substantial, Mixin as a dispather or helper) ==' parseFile(sys.argv[1], MyHandler2())
input file contents:
<hello>
world
{callBack1}
{callBack2}
<callBack1>
<callBack2>
hello
world
<callback3>
<mycallback>
Result
chenqi@chenqi-OptiPlex-760:~/mypro/python/xml-parser$ ./test.py input =======Substantial================ Substantial callback Substantial callback Substantial callback Substantial callback Substantial callback =======MyHandler(Directly inherit from Substantial========== MyHandler: doCALLBACK1 MyHandler: doCALLBACK2 MyHandler: doCALLBACK3 =======MyHandler2 (Inherit from Mixin and Substantial, Mixin as a dispather or helper) == MyHandler2: doCALLBACK1 MyHandler2: doCALLBACK2 MyHandler2: doCALLBACK3 chenqi@chenqi-OptiPlex-760:~/mypro/python/xml-parser$