alt.lang.jre: Get to know Jython

Enhance your productivity on the Java platform

Get to know Jython, in this first article in a new series introducing alternate languages for the Java Runtime Environment, alt.lang.jre. Jython is an implementation of the popular scripting language Python, but running on a JVM. For Python developers Jython is the best possible entry point to the Java platform; for Java developers it may be the strongest incentive to learn another language. Frequent developerWorks contributor and alternate language enthusiast Barry Feigenbaum introduces Jython and shows you what it can do to enhance your productivity on the Java platform.

Barry Feigenbaum, Ph.D., Sr. Consulting IT Architect, IBM

Barry FeigenbaumDr. Barry Feigenbaum is a member of the IBM Worldwide Accessibility Center, where he serves as a member of a team that helps IBM make its products accessible to people with disabilities. Dr. Feigenbaum has published several books and articles, holds several patents, and has spoken at industry conferences such as JavaOne. He serves as an Adjunct Assistant Professor of Computer Science at the University of Texas, Austin.



06 July 2004

Welcome to the new series alt.lang.jre. While most readers of this series are familiar with the Java language and how it runs on a cross-platform virtual machine (part of the JRE), fewer may know that the JRE can host languages besides the Java language. In its support for multiple languages (including some that pre-exist the Java platform) the JRE provides a comfortable entry point for developers coming to the Java platform from other backgrounds. It also gives developers who have rarely, if ever, strayed from the Java language the opportunity to explore the potential of other languages without sacrificing the familiarity of the home environment.

The ability to choose the right language for a variety of development scenarios is a tremendous advantage for almost any developer, but particularly those working on complex enterprise systems. Likewise, the adaptability of the JRE to multiple languages only solidifies the standing of the Java platform as an enterprise development environment.

This series of articles is a survey of many of the alternate languages for the JRE. Most of the languages you'll learn about in the series are open source and may be used for free, while a few are commercial products that must be purchased. Many are characterized as "scripting" languages that promote programmer productivity over machine efficiency; others are ports of popular mainstream languages. In all cases, the languages are supported by the JRE and are believed, by the authors, to enhance the dynamic and flexible nature of the Java platform.

In this first installment in the series, I'll focus on Jython, a scripting language that combines the ease of use of the Python language with the power and flexibility of the Java Runtime Environment . I've selected Jython as the first language to be introduced in this series because it is, in my opinion, among the most mature and productive of the alternate languages for the JRE. As such, my exploration of Jython will focus on the productivity enhancements it can lend to your Java programming efforts. Future installments in this series will introduce Groovy, JRuby, Rhino, Nice, and NetRexx, and many other exciting alternate languages for the JRE.

CLR vs JRE? No contest!

Microsoft has recently been promoting the .NET platform's Common Language Runtime (CLR) based on its ability to run multiple languages. Microsoft claims that language adaptability makes .NET a better development environment than the Java platform, which it claims is a single-language environment. As this series of articles will show, the Java platform is far more adaptable than Microsoft would have you believe. The JRE supports many languages other than the Java language, including some that pre-exist the Java platform. While the JRE does not support all the same languages as the CLR, it does provide a remarkably varied language landscape. In fact, the JRE compares favorably to the CLR as a multi-language development environment, as readers of this series will soon discover.

The case for Jython

Jython is an implementation of Python that fully supports the Python 2.1 syntax and most of its semantics while running on a JVM. It is an interpreted, interactive, object-oriented programming language that is written in 100% pure Java and seamlessly integrated with the Java platform. As such, Jython is both remarkably easy to learn and use and capable of running in any environment that supports a JVM -- including Microsoft Windows, Mac OS, and most Unix and Linux variants. Jython can also fully utilize all the classes and APIs provided by the Java Runtime Environment.

Jython's exceptional productivity lies in its marriage of the ease of use and flexibility of a scripting language, Python, with the robustness of the Java platform. Its simple, English-like syntax and intuitive semantics make Jython an ideal language for existing Python programmers, entry-level programmers, or programmers seeking a very rapid application development platform. Its string and text support features make it an exceptional platform for writing text-processing programs. And its built-in string manipulation functions (including regular expressions), as well as procedural and convenience features make it the ideal language for creating simple "scripting" programs.

Jython compares favorably to Visual Basic in its easy entry and adaptability, to many scripting languages in its emphasis on functionality, and to the Java language in both power and reliability. It is both a strong functional programming language and (by virtue of its object-oriented and modularized architecture) an excellent language for developing large applications.

In the following sections, I'll look closely at the mechanics underlying this powerful and versatile language.


Features of Jython

Jython syntax is line-oriented and similar to English while fully supporting the structured and object-oriented programming styles of languages such as Java and C++. Jython code can be directly interpreted or it can be translated to Java source that is automatically compiled to class files (see Resources). Compiled Jython classes can be executed independently from the Jython interpreter or used from Java code as if they were Java classes (for example, to develop applets or servlets).

Install and run the sample code

To run the Jython code samples in this article, you will need to have both Jython and a JRE installed. You can get Jython from the Jython home page and the Java platform from the Java platform home page (see Resources). Both of these sites include easily followed installation instructions. The samples in this article assume you have added the Jython install directory (which contains the jython.bat file) to your PATH.

As previously stated, Jython's productivity is its strongest asset. Some of the unique features of Jython (as compared to the Java language) are as follows:

  • Code can be entered and run line-by-line in interactive mode, which can improve learning and promote experimental use.
  • Variables are dynamically typed on assignment, so there is no need to pre-declare variables or use the new operator. These enhancements can significantly increase programming flexibility and also reduce the text size of your programs, thus increasing your productivity.
  • String operations are extensive and easily accessed (for example, x == y in Jython is the same as x.equals(y) in the Java language).
  • Adapter objects are automatically generated and automatically provide default Java interface implementations, making it much easier to implement event handler callbacks.
  • Natural indefinite precision integer values (that is, trivial access to a java.math.BigInteger-like type) and natural complex values allow Jython to easily support many more mathematical applications than are supported by the Java language.
  • Dynamic attributes (each class instance acts like a Java Map) allow far more dynamic class functionality.
  • Enhanced importing (like Java 1.5's import static) increase flexibility and modularity.
  • Classless and mainless (that is, open) code increase productivity for procedural programs (such as scripts).
  • Multiple public variables, functions, and/or classes per source file reduce the number of source files you must maintain, which simplifies large-scale development.
  • Default arguments on functions and methods greatly reduce the number of overloaded methods you need to create.
  • Keyword arguments on functions and methods increase the self-documentation and flexibility of your code.
  • Functional programming (functions are first-class objects) provide a very powerful and flexible style of programming that is lacking in the Java language.
  • Multiple inheritance supports a much richer inheritance hierarchy for the problems that require it.
  • Operator overloading allows new data types to be created that seamlessly integrate into the language.

What's classy about 'first class'?

First class entities can be represented as literal values, placed in variables and collections and passed as inputs and results of function calls. Thus, the primitive data types of the Java language, such as int, float, etc., are not first class. Generally an entity must be an object to be first class. In Jython all commonly used data types are first class.

This list gives you a good overview of the structural utility of Jython. In the sections that follow, I'll describe some of the elements that comprise Jython's productivity advantage -- namely data types and statement types.


First class data types

Jython supports many data types. All are first class and all are objects. Most support a literal representation that greatly simplifies their use. Many are more convenient to use than Java's types, especially the collection types. The most frequently used Jython data types are described below:

  • Null: An undefined value (like null in the Java language).
  • Integer: A normal (int in the Java language) or long (BigInteger in the Java language) integer number.
    -1  0  100
    -1L  1000000000000000000000000000000000000000000001L
  • Float: A fractional or exponential (like double in the Java language) number.
    1.0
    -1e6  0.000001e-10  1E11
  • Complex: A pair of floats supporting complex arithmetic.
    1j  -10J
    2-3j  1e6j
  • String: An immutable sequence of characters. There is no character type (use one character strings instead).
    "a string"
    'a string'
    """a long (possibly multi-line) string"""
    '''another (possibly multi-line) long string'''
    r'''^xxx(.*?)\.yyy(.*?)\.zzz(.*?)\.$'''
    'x'  "y" '\n' "\\"
  • Range: An immutable sequence of integers.
    range(10)
    range(10,0,-1)
    xrange(1,100000,10)
  • Tuple: An immutable sequence of any type (like java.util.Collections.unmodifiableCollection(someList)).
    ()  (1,)  (1,2,3)
    (1, "mixed", 2, "tuple")
    ((1,2),(3,4))
  • List: A mutable sequence of any type (like java.util.ArrayList).
    []  [1]  [1,2,3]
    [1, 'mixed', 2, 'list']
    [[1,2],[3,4]]
  • Map: A mutable collection of items (name/value pairs) (like java.util.Map). Names must be immutable and unique; values may be None.
    {}
    {1:'one',2:'two',3:'three'}
    {"one";1, "two":2, "three":3}
    {"x":1, "ints":(1,2,3), 
     "name":{"first":"Barry", last":"Feigenbaum"}}
  • Boolean: A true/false value based on other types.
    • false - 0 or empty: None 0 0.0 () []
    • true - non-0, not empty: 1 -1 0.0001 [1] [1,2,3] {"greeting":"Hello!"}
  • Function: Any function. Functions do not need to be members of classes.
    lambda x: x > 0
    
    def isPositive(x): return x > 0
    
    def addem(x,y,z): 
        return x + y + z
  • Class: Any class. Classes are namespaces for class attributes and functions (called methods).
    class MyClass: 
        x = 1
        y = 2
    
    class subclass(superClass):
        def method1(self): ...
    
        def method2(self, arg1, arg2): ...
  • Module: A source file (and namespace) that contains variable, function and/or class definitions. Any .py file that defines importable variables, functions and/or classes. If it does not define any of these then it is just called a script.

Statement types

Jython provides the statement types summarized in Table 1.

Table 1. Summary of Jython statement types
StatementCommentExamples
Expression Any expression. The results are discarded. Often used for their side effects.
(1 * 2) ** 3 / 4
"string"[2:] == "ring"
someFunction(1, 2, 3)
Assignment Assigns an expression to a target.
x = 3
x = f(1,32,3) * 10 + x
list[1:3] = [7, 8, 9 , 10]
Augmented Assignment Updates a target with an expression.
x *= 100
s += "…"
Unpacking Assignment Assigns elements of a sequence to multiple targets; very convenient for access to tuple and list members. Note that the expression 1,2,3 is a short form of (1,2,3).
x,y,z = 1,2,3
Multiple Assignment Assigns the same expression to multiple targets.
z = y = z = 10
Pass No operation.
pass
If
If/Else
If/Elif/Else
Conditional processing.
if x < 0: x = -x
if x == 3: print "It's three!"
if x == 1: ...
elif x == 2: ...
elif x == 3: ...
else: print "Bad value " + x
While Looping over a condition.
x = 10
while x > 0:
print x x -= 1
For Iterates over a sequence. Use range to iterate over a numeric sequence.
for i in range(10): print i
for c in "A string": print c
for i in (10, "Hello", 1e6): print func(i)
Continue Advances to the next loop (while/for) iteration.
for i in range(10):
if not testOk(i):
continue
:
Break Exits a loop (while/for)
for i in range(10):
if testBad(i):
break
:
Delete Removes a variable or sequence element(s) or class attribute.
del x
del list[3:5]
del x.attr1
Global Declares a reference to a global value; used in functions.
x,y,z = 0,1,2
def f(a,b,c):
global x,y,z
:
Print Prints expression(s) to a stream.
print "Hello World!"
print "Hello","World!"
print "Hello" + ' ' + "World!"
msg = "Name: %(last)s, (first)s"
data = {'last':"Feigenbaum", 'first':"Barry"}
print >>out, msg % data
Assert Asserts a condition is true.
def process(v):
assert v > 0, "Illegal value %i" % v
:
Import Imports all or part of a module.
import sys from sys
import argv from javax
import swing
from java.util import Map
Execute Executes a string/file as a subprogram. There is also a related function, exec, that executes a constructed string and returns its result. This support allows you to dynamically create programs.
globals = {'x':1, 'y':2, 'z':3}
locals = {'list':(1,2,3)}
code = "print x, y, z, list"
exec code in globals, locals
Try/Except Executes code within an exception handler.
try:
x = int(string)
except ValueError, e:
x = 0
Try/Finally Executes code with a cleanup routine.
f = open("test.dat")
try:
lines = f.readlines()
finally:
f.close()
Raise Creates and throws an exception.
def factorial(x):
raise ValueError, "x must be > 0"
:
Define Defines a function; arguments may be optional and/or keywords; Functions are generic which allows for very flexible programming.
def f(x,y=2,z=10):
return x+y+z
q = f(1,2) + f(3) + f(4,5,6)
s = f("a","b","c")
Return Returns from a function with an optional value.
return 10
Class Defines a class (a container for attributes and methods).
class X:
pass
class MyClass(SomeClass):
pass

Let's see it in code!

At this point you should have a growing understanding of the structure and syntax of Jython. What remains is best learned by examining a few simple but complete working programs. I'll start with the quintessential example program -- Hello World! -- which looks as follows in Jython:

Listing 1. Jython's Hello World!
print "Hello World!"

In Jython (as in Python) source files use the extension "py". The "Hello World" statement is a complete program when placed in a source file such as hello.py.

For comparison, take a look at the equivalent Java program, seen here in a file such as hello.java:

Listing 2. Java's Hello World!
public class hello {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

The Jython form is clearly much simpler, which is frequently the case. The nice thing about Jython, of course, is that the code can be directly interpreted or it can be translated to Java source and automatically compiled to class files. You can run the Hello World program by using the following Java command:

C:\>java -Dpython.home=C:\jython-2.1 -cp C:\jython-2.1\jython.jar 
      org.python.util.jython hello.py

Or, you can run the program by using the more convenient Jython script below:

C:\>jython hello.py

Echo, echo, echo.py!

Next, you'll try a more functional example, with a small program that lets you echo command-line arguments. For the program echo, you use the following code (in echo.py):

Listing 3. Example program for echoing command-line arguments
import sys
count = 1
for arg in sys.argv[1:]:
    print 'Argument %i=%s' % (count, arg)
    count += 1

Again, this complete Jython program reveals some key features of Jython. The first thing you'll note is that each line is a statement -- semicolons (;) are not required to end lines -- and that variables are not declared.

You should also note that command-line arguments are accessed via the built-in symbol sys.argv that is a sequence of strings. sys is a standard module that contains useful values and functions; many other standard modules exist for you to use. The first argv element (0) is the program name (that is, echo.py). To skip it you take a slice of the argv list, effectively starting at position one (1), and then iterate through the end of the list.

Looping is done via the for statement group. The for body is the indented lines after the for. The print statement demonstrates the use of Jython's string formatting feature (similar to C/C++'s printf and the new print feature of Java 1.5).

The above code could also be written more concisely as follows:

from sys import argv
for i in range(1, len(argv)): print 'Argument %i=%s' % (i, argv[i])

In this case, you use a range to index the sys.argv list. Because the argv variable is directly imported qualification is not required. Notice that the length of the argv list is obtained through the len function and not as a method; this is a Jython idiom and is common in many languages. Many other functions exist for you to use.


Let's factor -- with factorial.py!

For an exercise in class definition, you'll use the caching factorial calculator of factorial.py, shown in Listing 4.

Listing 4. The caching factorial calculator
class Factorial:
    ''' A factorial calculator '''
    seen = {} # cache of prior calculated values    

    def __init__ (self, value):
        self.__value = value

    def compute (self, value=None):        
        ''' calculate the result '''
        if value is None: value = self.__value   # default
        if   value < 0:          # bad arg!
            raise ValueError, 'arg < 0'
        elif value < 2:          # base case
            return 1L            # insure long integers are used
        else:                    # need to calculate
            if not value in Factorial.seen.keys():    # not done before?
                # calculate this value and cache it
                Factorial.seen[value] = value * \
                     Factorial(value - 1).compute()
            return Factorial.seen[value]  # get value from the cache

Here you see many new features of Jython. First off, comments are introduced by the sharp (#) token. A class or method can have a documentation comment string (which can be processed by tools similar to how JavaDoc is used) as its first line. Other than for assignment, statements are introduced by keywords. Class and method bodies are not enclosed in delimiters but are instead indicated by indention of their bodies.

Furthermore, classes are declared by the class statement. The def statement introduces methods. Class attributes are created by assignment in the class while instance attributes are created by assignment in the constructor method __init__. The seen variable is a dictionary. Instances are created by calling the class object as a function. Methods are invoked (as in the Java language) with the dot (.) operator.

You'll also note that the self variable is the method's receiver (like this in the Java language); within a method all references to instance attributes or methods of the class must be qualified with self. Class variables (as in the Java language) are qualified by the class name.

Functions can have default arguments, as shown for the value argument of the compute function. If the parameter value is omitted, then the __value instance attribute is used.

At this point it has become obvious that Jython supports all the features of the Java language but sometimes with different syntax. For example, Jython's raise statement is the same as the Java language's throw statement.

Testing factorial.py

You can test your Factorial class using the following code, which you'll also find in the file factorial.py (see Resources):

if __name__ == "__main__":
    from sys import argv
    if   len(argv) == 1: vals = range(10)
    elif len(argv) == 2: vals = range(int(argv[1]))
    elif len(argv) == 3: vals = range(int(argv[1]), int(argv[2]))
    else: print " Incorrect range"; vals = ()
    for i in vals:
        print "Factorial(%i)=%i" % (i, Factorial(i).compute())
    print "Cache:", Factorial.seen

In Jython, class definitions and tests cases can be combined. The if __name__... test above allows the test case code to run only if this file is run as a command. The file may also be imported by another file to reuse the Factorial class without running the test case. The test case consists of some simple command argument processing followed by a loop that calculates the factorial of the specified values (if any). Finally, the cache of values is printed.The jython factorial.py 5 10 command produces the following output:

Factorial(5)=120
Factorial(6)=720
Factorial(7)=5040
Factorial(8)=40320
Factorial(9)=362880
Cache: {9: 362880L, 8: 40320L, 7: 5040L, 6: 720L, 5: 120L, 4: 24L, 3: 6L, 2: 2L}

You might also notice in the example above that indefinite length integers can be calculated through the Jython long type (###L).


A GUI example

I'll end this introduction to Jython with a more complex program that creates a GUI. As you consider the simple AWT-based application, you'll see firsthand Jython's ability to be called from Java code and to access all the features of the Java platform.

You'll start by creating a GUI that is a Java Panel subclass called Scribble, as shown in Listing 5. Later, you'll create a Frame to display the Panel.

Listing 5. Class Scribble is a subclass of a Java Panel
from java.awt import BorderLayout as BL, Color, Button, Panel

class Scribble(Panel):
    """ A simple GUI example """

    def __init__ (self):  # constructor
        Panel.__init__(self, BL())
        self.add(Button('Clear', actionPerformed=self.doClear),
                         BL.SOUTH)
        self.mouseDragged = self.doDrag
        self.mousePressed = self.doPress
        self.__last = 0, 0

    def doClear (self, event):
        """ clear background """
        g = self.graphics
        g.color = self.background  
        g.fillRect(0, 0, self.size.width, self.size.height)

    def doDrag (self, event):
        """ draw line from last to here """
        g = self.graphics
        g.color = Color.black
        lx, ly = self.__last
        x = event.x; y = event.y
        g.drawLine(lx, ly, x, y)   # draw new line segment
        self.__last = x, y   # save coordinates

    def doPress (self, event):
        """ save click point """
        self.__last = event.x, event.y 

if __name__ == "__main__":
    def doClose (event):
        import sys
        sys.exit()
    from java.awt import Frame
    frame = Frame("Scribble", windowClosing=doClose)
    frame.add( Scribble() )
    frame.size = 400, 300
    frame.visible = 1

The first thing you'll likely notice about the code in Listing 5 is that multiple statements have been placed on one line, using semicolons as a separator. Lines can be continued after a comma. The import statement can import multiple classes and optionally rename them. The import statement is executable so it can be placed where needed, avoiding importing unnecessary symbols. Notice the nested doClose function. Also notice the lack of declarations and the lack of a new operator when creating class instances.

The self.__last instance attribute (which is a private attribute because it starts with a double underscore) holds the previous mouse click position. Each time a mouse drag event occurs, a (possibly quite short) black line is drawn between the saved point and the location of the event.

Notice also how the event handlers are defined. No Listener interface is used; instead attributes that match the interesting event handler entry points defined by the class (for example, actionPerformed) are set to Jython functions. The other unused entry points, if any, are automatically mapped to empty functions, thus there is no need to use Adapter classes. Also notice that any JavaBeans properties of Java objects (such as for the Graphics object g) can be accessed as Jython properties, not via get/set methods. This simplifies coding significantly, although you can still use the get/set methods if you like.

Figure 1 shows the Scribble GUI in use.

Figure 1. Sample Scribble GUI
Sample Scribble GUI showing the word 'Barry'

Conclusion

Sean McGrath, CTO of Propylon and frequent author, has said of Jython that it is the "most awesome Java productivity tool" without major vendor backing, and has also called it "the most compelling weapon the Java platform has for its survival into the Twenty-first century." In this first installment of alt.lang.jre, you've seen for yourself the ease and efficiency that Jython can bring to your development efforts on the Java platform. I've also begun, briefly, to discuss the importance of multi-language support to the future of the Java platform.

Next month you can continue your exploration of alternate languages for the JRE with an introduction to Groovy, a new language that combines some of the best aspects of Python, Ruby, and Smalltalk into an efficient, easy, and fun scripting language for the Java platform.

In the meantime, of course, there's lots more to be said about Jython, but it would take a book. See the Resources section to learn more about this powerful, easy-to-use language.


Download

DescriptionNameSize
Code samplej-alj07064code.zip1KB

Resources

  • Read the complete alt.lang.jre series a combined effort of several alternate language experts.
  • The two-part "Introduction to Jython" tutorial (developerWorks, May 2003) is an excellent starting point for learning more about Jython.
  • Visit the Jython homepage to download Jython and learn about file compilation.
  • Visit the Sun Java technology home page to download the most current version of the JDK, including the Java Runtime Environment..
  • Uche Ogbuji's "Charming Jython" (developerWorks, May 2003) offers a short, practical introduction to Jython.
  • Michael Nadel's recent "Use Jython to build JUnit test suites" (developerWorks, May 2004) offers a working example of how Jython can improve productivity in the execution of complex tasks on the Java platform.
  • Victor Yang's "Learn how to write DB2 JDBC tools in Jython" (developerWorks, April 2004) is another task-driven exploration of the power of Jython. See for yourself how Jython can simplify your DB2 JDBC programming.
  • Samuele Pedroni and Noel Rappin's Jython Essentials (O'Reilly, March 2002) is a solid, book-length introduction to Jython.
  • Jython for Java Programmers (New Riders, December 2001) focuses on application development, deployment, and optimization with Jython .
  • You can learn a lot about Jython by studying its predecessor, Python. Get started at the Python home page.
  • You'll find more of Sean McGrath's thoughts about Jython, the Java platform, and other development technologies on his frequently updated blogspot.
  • Browse for books on these and other technical topics.
  • You'll find hundreds of articles about every aspect of Java programming in the developerWorks Java technology zone.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10962
ArticleTitle=alt.lang.jre: Get to know Jython
publish-date=07062004