Jython Tips for Python Programmersby Noel Rappin, co-author of Jython Essentials
In my first article about Jython, I discussed the features of the Python scripting language and its Jython implementation that would be of greatest interest to Java programmers. Jython is a complete implementation of the Python programming language written in 100 percent pure Java, and allows easy access to Java libraries.
However, if you are already a Python programmer, then you know about the features of the Python programming language. For somebody already familiar with Python, the greatest attraction of using Jython is the ability to use any of the wide range of existing Java libraries and tools while being able to still use Python as the programming language.
Jython does its best to shield a Python programmer from the details of Java, but you'll still need to know some of those details to use Java objects and libraries most effectively from Jython.
This article contains 10 tips for using Java objects in Jython. I'll try not to assume much prior knowledge of Java, but space limitations prevent me from defining all Java terms in detail. Also, in this article when I need to differentiate the standard C implementation of Python, I'll refer to it as CPython.
A Java package is a collection of Java classes which are typically stored in the same directory, one class to a file. Just like Python modules, Java packages must be imported to Jython before use. In order to be imported, a Java package must be in either the Java
classpath or the Python
Java packages are imported as though they were Python modules, using the ordinary
import statement. You use the fully qualified name of the module for import. To import the
java.util packages, you would type:
import java.lang import java.util
Unlike CPython, in Jython you don't have to explicitly specify sub-packages. If you type the line:
in Jython, both
java.util (and all the other sub-packages of
java) are all available. This also works for standard Python modules -- in Jython, if you
import os, then the
os.path module is automatically imported.
Often, Jython programmers leave the full name of the Java package in the code, to emphasize the creation of Java objects. However, if you find that repetitive you can use the
as clause to shorten the package name, commonly done like this:
import java.lang as lang import java.util as util
It's recommended that you not use the
from version import statement:
from java import *
in production Jython code, because of the overhead of importing all of the standard libraries, and other potential problems. In general, it's a good idea to stick to
import for Java packages.
Once imported, Java objects are created using the same syntax as ordinary Python objects.
x = java.lang.String() z = java.util.HashMap()
Internally, Jython calls the appropriate Java constructor for the class given the number and type of arguments (see Tip 6 below for details) -- so the first line above calls the no-argument constructor for
java.lang.String, but the line:
x = java.lang.String("Hi")
calls the one-argument constructor that expects a
String. In other words, Jython is managing Java type information, so that you don't have to.
When creating Java objects (and only when creating Java objects), you can pass keyword arguments to the Jython constructor that are not part of the type signature of any Java constructor for that object. For example:
win = javax.swing.JFrame(size=(200,200))
For each keyword argument
x, Jython looks for a matching public method of the class
setX, and calls that method automatically. If there is no such set method, Jython raises an error.
Once created, Java objects can be used in Jython statements, and will nearly always behave as though they were native Python objects (some restrictions are listed below).
Java objects can be used as the test in an
while statement. The following Java object values are equivalent to Python false --
java.lang.Boolean FALSE, Boolean false, empty instances of
java.util.Hashtable, and any empty class implementing the interfaces
java.util.Collection. Note that unlike CPython, empty instances of Java strings are equivalent to Python true (empty Python strings are still false).
Any item of type
java.util.Iterator can be used as the list expression in a Jython
for statement. In addition, you can use standard Python index notation (such as x) for any subclass or implementer of
java.util.Map. However, slice access (such as x[3:5]) is not supported on Java objects.
Any subclass of
java.lang.Exception can be raised and caught from within Jython using the normal Python
Normally from Jython you can call any Java method or field designated as
public in the Java class. You can get at private methods by changing Jython's start-up options.
Jython also allows you to avoid the ubiquitous Java get/set methods, allowing your program to have a more Pythonic style. When Jython sees a line of code such as:
x = javaObj.attribute
a Java call of the method
javaObj.getAttribute(), if such a method exists, is automatically generated. Similarly, an assignment to
javaObj.attribute is converted to a call to
Frequently, you will need to call a Java method that requires a Java array as an argument. Under normal circumstances, Jython will automatically convert a Python list or tuple to an array of the appropriate type when needed. This assumes that each item in the list or tuple can be converted to the appropriate type -- if not, Jython will raise a runtime error. So the Jython list
[1, 2, 3] can be converted to a Java
java.lang.Object as needed (but not, for example, to a
However, that conversion creates a copy of the list, and in some cases that's not what you want. For example, if the method you are calling changes the list in-place, the change will not propagate back to the Jython code, since the array is only a copy of the Jython list. Jython provides the
jarray module to simplify the direct creation of Java arrays when needed.
You can create blank arrays with the
>>> import jarray >>> jarray.zeros(5, 'i') array([0, 0, 0, 0, 0], int)
The first argument is the length of the array, and the second is either a character representing a basic type, or a Java class name.
>>> jarray.zeros(4, java.lang.String) array([None, None, None, None], java.lang.String)
You can create arrays directly from Python sequences, by using the
>>> jarray.array([8, 9, 2, 1], 'i') array([8, 9, 2, 1], int)
Now, the first argument is a Python sequence, and the second is still the class or type signature.
In the case where the Java method is overloaded and has more than one definition, Jython will attempt to match the call to the correct method based on the number and runtime type of the arguments.
Although the details can get complex, the basic idea is simple: Jython first attempts to choose a method with the same number of arguments as the call, and if there is more than one, it chooses the method whose required type is most similar to the calling object. In general, Jython prefers methods with basic Java types over methods with Java object types.
A Jython object can be declared as a subclass of a Java object by using the standard Python syntax:
class JythonString(java.lang.String): pass
Java interfaces can also be implemented in this way. Jython does not do a compile-time check to determine if all methods in an interface are actually defined -- calling an undefined method will raise a runtime exception.
Although Jython does have multiple inheritance, there is one limitation concerning Java objects. A Jython class can have at most one Java ancestor. This is true whether the ancestor is a direct parent, or an indirect parent via another Jython class.
Java subclasses behave differently when constructed. If a Jython class has a Java parent, and that parent has a no-argument constructor, that constructor is automatically called at the end of the Jython class'
__init__ method, or before a Java attribute is used within that
__init__ method. This is different from the normal Python behavior, where a parent class constructor is never called automatically. This is done to ensure that the Java objects are properly initialized before use.
Unlike ordinary Python objects, you cannot create new attributes in a Java object instance simply by assigning to it -- the instance must have been declared in Java. Attempting to assign to an instance of a Java class that does not exist will raise an error.
>>> x = java.util.ArrayList() >>> x.language = 'english' Traceback (innermost last): File "console", line 1, in ? TypeError: can't set arbitrary attribute in java instance: language
To work around this limitation, you can create a subclass of the Java class -- it can be an empty subclass. You can then add attributes to instances of the subclass:
>>> class NewArrayList(java.util.ArrayList): ... pass ... >>> x = NewArrayList() >>> x.language = 'english' >>> x.language 'english'
Java objects cannot be serialized using the standard Python
cPickle modules. Both Java and Jython objects can be serialized using normal Java serialization. However, when deserializing a Jython object you cannot use the normal
java.io.ObjectInputStream class, you must use the Jython-specific
org.python.util.PythonObjectInputStream, as shown here:
import java.io as io import org.python.util as util class TestClass(io.Serializable): def __init_ _(self, value=0): self.value = value self.message = "Serialized" def toString(self): return "Message: %(message)s value: is %(value)s" % self.__dict_ _ instance = TestClass(3) outFile = io.FileOutputStream("test.ser") outStream = io.ObjectOutputStream(outFile) outStream.writeObject(instance) outFile.close( ) inFile = io.FileInputStream("test.ser") inStream = util.PythonObjectInputStream(inFile) readInstance = inStream.readObject( ) print readInstance.toString( ) Message: Serialized value: is 3
If you do not use the
PythonObjectInputStream, you will get a runtime error because the ordinary Java
ObjectInputStream has difficulty finding and recreating the dynamically loaded proxy classes used for Jython's Java inheritance.
Finally, here are a few of the most important differences between Jython and Cpython, not directly related to object usage:
For more information on Jython, see the main Jython site at http://www.jython.org, and get a copy of our recent book, Jython Essentials.
Noel Rappin has a Ph.D. in computer science from the Georgia Institute of Technology, where his research included methods for teaching Object-Oriented Programming and Design. He has extensive production experience in both Java and Python.
Return to the Python DevCenter.
Copyright © 2009 O'Reilly Media, Inc.