This example shows off several useful features of Python including introspection, dynamic loading, first-class functions and flexible except clauses.
At work I have some Java code that uses XPath support from the Xalan class org.apache.xpath.XPathAPI. In Java 1.4 this class is provided with the JRE. In Java 1.5 they moved the class to com.sun.org.apache.xpath.internal.XPathAPI. I need to run with either version of Java. I prefer not to bundle Xalan with my program, so I wrote a wrapper that dynamically locates the correct version and dispatches to it:
// The XPathAPI is in different packages in Java 1.4 and 1.5.
// Use introspection to find the right one
private static Method __selectSingleNode;
static {
// Look for the XPathAPI class in two places
Class XPathAPI = null;
try {
XPathAPI = Class.forName("org.apache.xpath.XPathAPI");
} catch (ClassNotFoundException e) {
try {
XPathAPI = Class.forName("com.sun.org.apache.xpath.internal.XPathAPI");
} catch (ClassNotFoundException e1) {
}
}
// Get the methods we support
try {
__selectSingleNode =
XPathAPI.getMethod("selectSingleNode",
new Class[] { Node.class, String.class} );
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
}
/** XPathAPI.selectSingleNode */
public static Node selectSingleNode(Node node, String xpath) {
try {
return (Node)__selectSingleNode.invoke(null, new Object[] { node, xpath });
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
Wow, what an ugly mess! What would it look like in Python?
The initial static block would become a conditional import:
try:
import org.apache.xpath.XPathAPI as XPathAPI
except ImportError:
import com.sun.org.apache.xpath.internal.XPathAPI as XPathAPI
That was easy - and wait - we're done now! The client code can call XPathAPI.selectSingleNode() and it will work!
But suppose for the sake of example we want to get a reference to selectSingleNode using introspection. That is as simple as
__selectSingleNode = getattr(XPathAPI, 'selectSingleNode')
This __selectSingleNode is itself a callable function (not a wrapper around a function) so clients can call it directly; the selectSingleNode() wrapper is not needed at all.
I have omitted the exception handling in the Python code because these exceptions are fatal and might as well terminate the program. If I wanted to catch them I could use an except clause with multiple exception types, instead of multiple except clauses, something like this:
try:
__selectSingleNode = ...
except (SecurityException, NoSuchMethodException), e:
e.printStackTrace()
|