Multiple programming languages Multiple Languages-2. . . . . . Create a language using Jython, creating an interpreted language in your program is extremely simple. Consider the example of the "Thinking In Java" Chapter 8 Greenhouse Controller. In that case, you will want the end user - that is also the person who manages Greenhouse - can control the entire system through configuration, so a simple scripting language has become an ideal solution. To create this language, we only need to write a set of Python classes simple, and each class is added to a (static) master lin list. Public data and behavior will be found by Factor to the base class called EVENT. Each EVENT object includes an action string (for simplicity - actual application, you should arrange some functionALITY) and run the event (Event) setting time. The constructor initializes these member variables, then adds the newly created EVENT object to a static linked list called Events (internally defined in the class, but outside of all methods, so it is static) static linked list.
#: interpreter: Greenhouselanguage.py class event: event: Events = [] # static def __init __ (self): self.action = action self.time = time evenet.events.Append (self) # @ used by sort () THIS WILL CAUSE # Comparisons To Be Based Only on time: Def __cmp__ (self): if self.time
The above file is now a module, which can be included in an additional Python program to define all classes contained in that program. However, we don't have to use ordinary Python programs, we use Java Jython. This is actually very simple: you only need to introduce some Jython class, create a PythonInterpreter object, and then cause the Python files to be loaded: // - interpreter: GreenHouseController.javapackage interpreter; import org.python.util.PythonInterpreter; import org .python.core *;. import junit.framework *;. public class GreenHouseController extends TestCase {PythonInterpreter interp = new PythonInterpreter (); public void test () throws PyException {System.out.println ( "Loading GreenHouse Language"); interp .execfile ( "GreenHouseLanguage.py"); System.out.println ( "Loading GreenHouse Script"); interp.execfile ( "Schedule.ghs"); System.out.println ( "Executing GreenHouse Script"); interp.exec ("Run ()");} public static void main (string [] args) throws pyexception {junit.textui.teestrunner.run (GreenhouseController.class);}} ///: ~
The Pythoninterpreter object is a complete Python interpreter that accepts commands from the Java program. One of the commands is Execfile (), which tells the interpreter to perform all the statements contained in the particular file it find. By performing GreenhouseLanguage.py, all classes in that file are loaded into the Pythoninterpreter object, so the interpreter "has" Greehouse controller language. Schedule.GHS is the file created by the end user to control Greenhouse. Here is an example: // :! Interpreter: schedule.ghsbell (7.00) Thermostatday (6.00) Wateron (3.30) Lighton (1.00) THERMOSTATATNIGHT (5.45) ///: ~ This is Interpreter Design The purpose you want to achieve: the configuration of your program is as simple as possible for end users. You can almost do not costly with Jython. PythonInterpreter has a method for use is exec (), by which you can send a command to the interpreter. In the above example, the Run () function is called by exec (). Remember, you have to run this program, you must go to http://jython.sourceforge.net download and run Jython (In fact, you just need to put Jython.jar to your classpath). After these do this, it can run like other Java programs. Control Interpreter Controlling The Interpreter is just an interpreter and allows it to run an external script. The rest of this chapter, we will tell more complicated ways to interact with Python. To apply more control over the Java range, the easiest way is to send data to the interpreter, and then retrieve data from it (PULL DATA Back Out).
Submitted Data Putting Data in In order to insert data to your Python program, the PythonInterpreter class has a seemingly simple method: set () .. In fact, SET () can accept different types of data and convert them. The following example is a relatively comprehensive practice of SET () different usage, which provides a fairly complete explanation.
// - interpreter: PythonInterpreterSetting.java// Passing data from Java to python when using // the PythonInterpreter object.package interpreter; import org.python.util.PythonInterpreter; import org.python.core *; import java.util.. *; import com.bruceeckel.python *;. import junit.framework *;. public class PythonInterpreterSetting extends TestCase {PythonInterpreter interp = new PythonInterpreter (); public void test () throws PyException {// It automatically converts Strings // into native Python strings: interp.set ("a"); Interp.exec ("Print A"); Interp.exec ("Print A [5:]"); // a SLICE // IT Also knows what to do with arrays: string [] s = {"how", "do", "you", "do?"}; interp.set ("b", s); interp.exec ("for x IN B: Print X [0], X "); // set () Only takes objects, so it can't // figure outprimities. instead, // you have to use wrappers: interp.set (" c " , New Pyinteger (1)); Interp.Set ("D", New Pyfloat (2.2)); Interp.exec ("Print C D "); // you can also use java's object wrappers: interp.set (" c ", new integer (9)); interp.set, new float (3.14)); interp.exec (" Print C D "); // define a python function to print arrays: interp.exec (" Def PRT (x): / n " " Print X / N " " for i in x: / n " " Print i, / n " " Print X.__ class __ / n "); // Arrays Are Objects, SO IT HAS No Trouble // Figuring Out The Types Contained in Arrays: Object [] Types =
{New Boolean [] {True, false, false, true}, new char [] {'a', 'b', 'c', 'd'}, new byte [] {1, 2, 3, 4} New int [] {10, 20, 30, 40}, new long [] {100, 200, 300, 400}, new float [] {1.1F, 2.2F, 3.3F, 4.4F}, New Double [ ] {1.1, 2.2, 3.3, 4.4},}; for (INT i = 0; I "M [1], M [1] .__ class__"); // NOT A Python Dictionary, So this fails: //! interp.exec ("for x in m.keys ():" //! "Print x, m [x] "); // to Convert a map to a python dictionary, // use com.bruceeckel.python.pyutil: interp.set (" m ", pyutil.topyDictionary (m)); interp.exec ("Print M, M.__ Class__," "M [1], M [1] .__ Class__"); Interp.exec ("for x in m.keys (): Print X, M [x]"); Public static void main (string [] args) throws pyexception {junit.textui.teestrunner.Run (Pythoninterpretersetting.class);}} ///: ~ For Java, most of the true objects (REAL OBJECTS) and The difference between the basic type (Primitive Types) will always brought trouble. In general, if you pass it to set (), the method is a normal object, it knows how to handle it, but if you want to pass a basic type (Primitive Type), you must have Conversion. One approach is to create a "PY" type, such as Pyinteger and Pyfloat, but in fact you can also use the Java's own Object overchart, such as Integer and Float, which may easily remember. The previous part of the above program You will see an exec () containing the following Python statement: Pint a [5:] The semicolon in the index statement indicates that this is a Python slice (SLICE), the so-called slice is from one original array An element within a range is generated. Here, it produces a new array containing the last element of the original array from the 5th element. You can also generate elements No. 3 to No. 5 or "a [: 5]" to generate No. 0 to No. 5. The reason for using a slice in this statement is to ensure that Java's String is indeed converted to a Python string, and the Python string can be treated as a character array. You will see that we can use exec () to create a python function (although there is a little awkward). The PRT () function prints the entire array, then (To Make Sure It's A Real Python Array) traverses each element of the array and print it out. Finally, it prints the class name of the array, we can see what transition occurs (Python has not only runtime information, it also has something comparable to Java). The PRT () function is used to print an array of basic types from Java. Although you can use Set () to introduce a Java's ArrayList in the interpreter, you can also index it as an array, but trying to generate a slice from it. In order to completely convert it into an array, one method is to take out a Java array using toarray (), then pass it to the interpreter. The set () method converts it into a class provided by PyaRray - Jython - it can be treated as a python array (you can also express a Pyarray, but there seems to be no necessary). Finally, we created a map and passed it directly to the Unexpen. Although you can have a true Python Dictionary (Dictionary), you can't call the method like Keys (). There is no direct manner to convert a Java's MAP into a Python dictionary, so I wrote a small program called topyDictionary () and put it as a static method for com.bruceeckel.python.pyutil. It also includes some small programs extracted from the Python array to Java List and extract data from the Python dictionary to Java Map. // - com: bruceeckel: python: PyUtil.java// PythonInterpreter utilitiespackage com.bruceeckel.python; import org.python.util.PythonInterpreter; import org.python.core *; import java.util *; public class PyUtil.. {/ ** Extract a Python tuple or array into a Java List (which can be converted into other kinds of lists and sets inside Java). @param interp The Python interpreter object @param pyName The id of the python list object * / public static List toList (PythonInterpreter interp, String pyName) {return new ArrayList (Arrays.asList ((Object []) interp.get (pyName, Object [] class)).);} / ** Extract a Python dictionary into a Java map @param interp The Python interpreter object @param pyName The id of the python dictionary * / public static map toMap (PythonInterpreter interp, String pyName) {PyList pa = ((PyDictionary) interp.get (pyName)) items ().; Map map = new hashmap (); while (pa .__ len __ ()! = 0) {Pytuple PO = (PyTuple) PA.POP (); Object Firs T = po .__findItem __ (0) .__ tojava __ (Object.class); Object Second = Po .__ FindItem __ (1) .__ tojava __ (Object.class); map.put (first, second);} return map;} / ** Turn a Java Map into a PyDictionary, suitable for placing into a PythonInterpreter @param map The Java Map object * / public static PyDictionary toPyDictionary (Map map) {Map m = new HashMap ();. Iterator it = map.entrySet () iterator (); Whose (it.hasnext ()) {map.entry E = (map.entry) it.next (); m.put (py.java2py (E.GetKey ()), Py.java2py (E.GetValue ());} // pydictionary constructor Wants a hashtable: return new pyDictionary (new hashtable (m));}} ///: ~ Below is the code (black box) unit test code: // - com: Bruceeckel: Python: Test.javaPackage com.bruceeckel.python; import org.python.util.pythoninterpreter; import junit.util. *; Import junit.framework. *; Public class test extends testcase {pythoninterpreter pi = new pythoninterpreter (); public void test1 () {pi.exec ("TUP = ('feed",' fi ',' fo ',' fum ',' fi ') "); List lst = pyutil.tolist (pi," tup "); system.out.println (LST); system.out.println (new hashset (lst));} public void test2 () {pi.exec "INTS = [1, 3, 5, 7, 9, 11, 13, 17, 19]"); List Lst = Pyutil.tolist (Pi, "INTS"); System.out.Println (LST);} PUBLIC Void test3 () {pi.exec ("dict = {1: 'a', 3: 'b'," "5: 'c', 9: 'd', 11: 'e'}"); map MP = pyutil.tomap (pi, "dict"); system.out.println (mp); public void test4 () {map m = new hashmap (); M.PUT ("twas", new integer (11) ); M.PUT ("Brillig", New Integer (27)); M.PUT ("and", New Integer (47)); M.PUT ("THE", New Integer (42)); M.PUT ("SLITHY", New Integer (33)); M.PUT ("Toves", New Integer (55)); system.out.println (m); pi.set ("M), Pyutil.topyDictionary (M)); PI.EXEC (" Print M "); PI.exec (" Print M [' SLITHY '] ");} public static void main (string args []) {junit.textui.teestrunner.run (test.class);}} ///: ~ In the next section we will tell (data) to extract the usage. Removing data Getting Data Out There are many different ways to extract data from PythonInterpreter. If you just call the get () method, pass the object identifier as a string to it, it will return a PyObject (part of the support class provided by Org.Python.core). It can be "CAST" in the __tojava __ () method, but there is a better way than this: 1. There is some very convenient way, such as py2int (), can accept a pyobjec and convert it into a number Different types. 2. GET () has an overloaded version accepts the expected Java Class object as the second parameter and generates an object with its runtime type (So in your Java code). You still need to be CAST on the results. Using the second method, taken an array from PythonInterpreter to be very simple. This is especially useful, because Python is excellent in string and file processing, so you will usually ask the results as a string array. For example, you can use Python's GLOB () function for wildcard expansion, just like the next example: // - interpreter: pythoninterpreter home the pythoninterpreter Object. package interpreter; import org.python.util.PythonInterpreter; import org.python.core *;. import java.util *;. import com.bruceeckel.python *;. import junit.framework *;. public class PythonInterpreterGetting extends TestCase { PythonInterpreter interp = new PythonInterpreter (); public void test () throws PyException {interp.exec ( "a = 100"); // If you just use the ordinary get (), // it returns a PyObject: PyObject a = interp .get ("a"); // there's not much you can do with a generic // pyobject, but you can print it out: system.out.println ("a =" a); // if you know the Type it's supposed to be, // you can "Cast" IT Using __tojava __ () to // That Java Type and manipulate it in java. // to use 'a' as an int, you must use // the integer wrapper class : Int Ai = (Integer) a .__ tojava __ (Integer GER.CLASS)))) .intValue (); // there is also convenience functions: ai = py.py2int (a); system.out.println ("ai 47 =" (Ai 47)); // you CAN Convert IT to Different Types: float af = py.py2float (a); system.out.println ("AF 47 =" (AF 47)); // if You try to cast it to an inappropriate //// Type You'll get a runtime exception: //! String as = (string) a .__ tojava __ (//! string.class); // if you know the Type, a more useful method // is the overloaded get () Takes the // desired class as the 2nd argument: interp.exec ("x = 1 2"); int x = (((((((((((((() INT x = Integer). INTVALUE (); system.out.println ("x =" x); // Since python is so good at manipulating // strings and files, you Will often need to // extract an array of strings. Here, a file // is read as a python array: interp.exec ("LINES =" "open ('pythoninterpretergetting.java')" ".readLines () "); // pull it in as a java array of string: string [] lines = (String []) interp.get (" lines ", string []. Class; for (int i = 0; i <10 ; i ) System.out.Print (Lines [i]); // as an esample of useful string tools, // global expansion of ambiguous file name // using glob is very useful, but it it's not // part of the standard Jython Package, SO // You'll Have to make su consement what you // python path is set to include these, or // That You Deliver The next Your application. Interp.exec ("from glob import glob"); interp.exec ("Files = Glob ('*. java')"); string [] files = (String []) Interp.get ("Files", String []. Class; for (int i = 0; i Pyutil.tolist (Interp, "TUP"); System.out.Println (TUP); // IT really is a list of string objects: system.out.println (tup.get (0) .getClass ()); / / You can easily convert it to a set: set tups = new hashset (TUP); system.out.println (tups); interp.exec ("INTS = [1, 3, 5, 7, 9, 11, 13, 17, 19] "); List INTS = Pyutil.tolist (Interp," INTS "); System.out.Println (INTS); // IT Really Is A List of Integer Objects: System.out.Println ((INTS). Get (1)). getClass ()); // if you have a python dictionary, it can // be extracted into a java map, again with // com.bruceeckel.pyutil: interp.exec ("DICT = {1 : 'a', 3: 'b', " " 5: 'c', 9: 'D', 11: 'e'} "); Map Map = Pyutil.Tomap (Interp," DICT "); system .out.println ("map:" map); // IT really is java objects, not pyobjects: iterator it = map.entryset (). Iterator (); map.entry E = (map.entry) it.next (); System.out.println (E.GetKey (). GetClass ()); System.out.Println (E.GetValue (). GetClass ());} Public STA TiC void main (string [] args) throws pyexception {junit.textui.teestrunner.run (Pythoninterpretergetting.class);}} ///: ~ The last two examples show off from Python (tuples) and Links (Lists The data is extracted into Java Lists and extracts data from the Python dictionary to Java Maps. The above two cases need to use more processing methods provided by the standard Jython library, so I wrote some small programs in com.bruceeckel.pyton. Pyutil: Tolist () is used to generate a list from a Python sequence, Tomap () is used to generate a map from the Python dictionary. The method provided by Pyutil makes it easier to deliver important data structures between Java and Python. Multiple interpreters Multiple Interpreters must be mentioned, you can declare multiple PythonInterpreter objects in a program, each object has its own namespace: // - interpreter: multiplejythons.java/ You Can Run Multiple Interpreters , each // with its own name space.package interpreter; import org.python.util.PythonInterpreter; import org.python.core *;. import junit.framework *;. public class MultipleJythons extends TestCase {PythonInterpreter interp1 = new PythonInterpreter ( ), Interp2 = new pythoninterpreter (); public void test () throws pyexception {interp1.set ("a", new pyinteger (42)); interp2.set ("a", new pyinteger (47)); interp1.exec ("Print A"); Interp2.exec ("Print A"); PyObject x1 = interp1.get ("a"); PyObject x2 = interp2.get ("a"); system.out.println ("a from Interp1: " x1); System.out.Println (" a from interp2: " x2);} public static void main (string [] args) throws pyexception {junit.textui.teestrunner.run }} ///: ~ When you run the program, you will see that the value of the A included in each Pythoninterpreter is different. . . . . . . table of Contents