- 论坛徽章:
- 0
|
alt.lang.jre: Get to know Jython
Enhance your productivity on the Java platform
Document options
Print this page
E-mail this page
Sample code
Rate this page
Help us improve this content
Level: Introductory
Barry Feigenbaum, Ph.D. (
feigenba@us.ibm.com
), Sr. Consulting IT Architect, IBM
06 Jul 2004
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.
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.
Back to top
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.
Back to top
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 in Table 1.
Table 1. Summary of Jython data types
Type Comment Example
Null An undefined value (like null in the Java language). None
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.
Back to top
Statement types
Jython provides the statement types summarized in Table 2.
Table 2. Summary of Jython statement types
Statement Comment Examples
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
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
Back to top
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
Back to top
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)
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.
Back to top
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
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).
Back to top
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
Back to top
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.
http://www-128.ibm.com/developerworks/java/library/j-alj07064/
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/19919/showart_485570.html |
|