Introduction

Jython, lest you do not know of it, is the most compelling weapon the Java platform has for its survival into the 21st century.

-Sean McGrath, CTO, Propylon

Topics

  • What is Python or Jython?
  • Some examples showing Python source and Java source.
  • Discuss alternatives to Java & Python integration
  • Walk through a simple runtime example

What Is Python?

  • An interpreted, interactive, object-oriented programming language
  • Dynamic typing & high level data structures
  • Higher productivity and easier maintenance
  • Fewer lines of code than comparable Java program

What Is Jython?

  • The Java implementation of the Python programming language
  • Dynamic compilation to JVM byte codes
  • Seamless integration with Java libraries
  • Interactive exploration and prototyping of all Java libraries
  • History
    • Original implementation by Jim Hugunin in 1997
    • Handed off to many primary maintainers

Differences - Python & Jython

Python

  • C
  • Multi-platform
  • Compiles to .pyc
  • Extend with C
  • GIL
  • Python Garbage Collection

Jython

  • 100% Java
  • Any JVM (currently 1.1+)
  • Compiles to .class
  • Extend with Java
  • Truly multi-threaded
  • Java garbage collection

General Bits

  • del is not reliable because the Java garbage collector is used

  • Java only has Unicode strings

  • Cannot mix Python and Java classes in multiple inheritance

  • Java instances cannot have dynamic attributes

  • Boolean type difficult to address

    public void do(int i);
    public void do(boolean b);

  • Jython changes with two fronts

    • Keeping up with CPython language changes
      • new-style classes
      • list comprehensions
      • generators
    • Keeping up with Java language changes
      • enum
      • auto-boxing
      • vargs
      • generics (not necessary in Python)
      • annotations
      • StackTraceElement

Differences - Python & Java

  • Python is dynamically typed; Java is statically typed
  • Python has only unchecked exceptions; Java has both checked and unchecked
  • Python uses whitespace for scoping
    • In my experience, almost every Java program (not machine generated) does
  • Python has no seperate compilation step
  • Python has multiple, functional inheritance; Java has multiple hierarchical inheritance but singular functional inheritance
  • Python has richer built-in data structures (lists, dicts, tuples, everything is an object)
  • No operator overloading in Java (personal annoyance)

What Does Jython Do Well?

  • Protyping
  • Java investigation
    >>> from java.util import Date
    >>> d = Date()
    >>> print d
    Sat Jan 08 16:26:16 CST 2005
    >>> from java.util import Random
    >>> print dir(Random)
    ['__init__', 'nextBoolean', 'nextBytes', 'nextDouble', 'nextFloat',
    'nextGaussian', 'nextInt', 'nextLong', 'seed', 'setSeed']
    >>>
  • Bean properties accesible
    >>> print Date().time
    1105500911121
  • Glue together libraries already written in Java
  • Excellent embedded scripting language
    • Object Domain UML Tool
    • PushToTest
    • Drools

What Does Jython Not Do Well?

  • Anything Java can’t do
  • Access Python modules written in C
  • C libraries without JNI
  • COM libraries without JNI
  • missing Unix-ish functionality without JNI
    • os filesystem methods
    • signals

What Java Libraries Are Superior To Python?

  • Servlets
  • JMS
  • J2EE
  • Javadoc
  • Swing is often considered superior to other GUI toolkits - I have little experience

Jython’s Production Viability

  • Used by BEA for managing Weblogic
    • WebLogic Server Scripting Tool
  • Propylon
  • Numerous internal systems
    • Financial services
    • App support & operations
  • Sun hosted a dynamic languages summit for languages targeting the JVM

Examples

  • Differences in syntax and language features between Java and Python

Examples - Lists

  • Java

    import java.util.List;
    import java.util.Iterator;
    import java.util.ArrayList;
    
    public class ExLists {
    
      public static void f(Object o) {
        System.out.println(o);
      }
    
      public static void main(String[] args) {
        List t = new ArrayList();
        t.add(new Integer(1));
        t.add(new Integer(2));
        t.add(new Integer(3));
    
        // loop the list
        for(Iterator i=t.iterator();i.hasNext();) {
          Object o = i.next();
          ExLists.f(o);
        }
      }
    }

  • Jython

    def f(x):
      print x
    
    [f(x) for x in T]

Examples - Dicts

  • Java

    import java.util.Map;
    import java.util.HashMap;
    
    public class ExDicts {
    
      public static void main(String[] args) {
        Map m = new HashMap();
        m.put("a", new Integer(1));
        m.put("b", new Integer(2));
        m.put("c", new Integer(3));
      }
    
    }

  • Jython

    d = {"a":1, "b":2, "c":3}

Examples - Reading files line by line

This one is not fair ;)

  • Java

    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.LineNumberReader;
    import java.io.FileNotFoundException;
    
    public class ExReadFile {
      public static void main(String[] args) {
        FileReader r = null;
        File f = new File("jython-presentation.py");
        try {
          r = new FileReader(f);
        } catch (FileNotFoundException e) {
          return;
        }
    
        LineNumberReader lnr = new LineNumberReader(r);
    
        String line = null;
        do {
          try {
            line = lnr.readLine();
          } catch (IOException e) {
            line = null;
          }
          if (line != null) {
            System.out.println(line);
          }
        } while(line != null);
    
        try {
          r.close();
        } catch (IOException e) {}
    
      }
    }

  • Jython

    fp = open("jython-presentation.py")
    try:
      for line in fp:
        print line,
    finally:
      fp.close()

Examples - Exception Handling

  • Java
    public class ExException {
      public static void main(String[] args) {
        try {
          int a = 1;
          int b = a/0;
        } catch (ArithmeticException e) {
          e.printStackTrace();
        } catch (NullPointerException e) {
          e.printStackTrace();
        }
      }
    }
  • Jython
    try:
      a = 1
      b = a/0
    except (ZeroDivisionError, ValueError, NameError), e:
      print e

Examples - Reflection

  • Java
    import java.util.ArrayList;
    import java.lang.reflect.Method;
    import java.lang.reflect.InvocationTargetException;
    
    public class ExReflection {
      public static void main(String[] args) {
        List a = new ArrayList();
        a.add(new Integer(1));
    
        Method g = null;
        try {
          g = a.getClass().getMethod("get", new Class[] {Integer.TYPE});
        } catch (NoSuchMethodException e) {
          e.printStackTrace();
        }
    
        System.out.println(g);
    
        try {
          System.out.println(g.invoke(a, new Object[] {new Integer(0)}));
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        } catch (InvocationTargetException e) {
          e.printStackTrace();
        }
      }
    }
  • Jython
    from java.util import ArrayList
    
    a = ArrayList()
    a.add(1)
    
    g = getattr(a, "get")
    
    print g
    print g(0)
    
    # alternatively
    
    g = a.get

Examples - Subclassing

  • Simple subclassing example
    from java.util import ArrayList
    
    class CountingArrayList(ArrayList):
      def __init__(self):
        ArrayList.__init__(self)
        self.count = 0L
    
      def get(self, index):
        self.count += 1
        return ArrayList.get(self, index)
    
    a = CountingArrayList()
    a.add(1)
    a.add(1)
    a.add(2)
    a.add(3)
    a.add(5)
    
    print "len says: %02d, size says: %02d" % (len(a), a.size())
    
    a.get(0)
    a.get(4)
    
    print "accessed %02d times" % (a.count)
    Collections are proxied so __len__ and other magic methods work as expected (most of the time).

Examples - Servlets

  • Java

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class HelloWorldServlet extends HttpServlet {
      public void doGet(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("text/html");
        try {
          PrintWriter out = response.getWriter();
          out.println(
            "<html>"
            + "<head><title>Hello World Servlet</title></head>"
            + "<body>Hello World Servlet at " + new Date() + "</body>"
            + "</html>"
          );
        } catch (IOException e) {
          // now what?
        }
      }
    }

  • Jython

    from javax.servlet.http import HttpServlet
    from java.util import Date
    
    class HelloWorldServlet(HttpServlet):
      def doGet(self, req, res):
        res.setContentType("text/html");
        out = res.getOutputStream()
    
        print >> out, ("<html>"
                       "<head><title>Hello World Servlet</title></head>"
                       "<body>Hello World Servlet at %s<body>"
                       "</html>" % Date())
        out.close()
        return
    PyServlet (included with Jython) is registered to handle all requests for files with .py extension. The servlet loads the .py file and executes it. All code is written in Python.

Examples - Databases

  • Java

    import java.sql.*;
    import java.util.*;
    
    public class JDBCExample {
      public static void main(String[] args) throws Exception {
        Class.forName("org.postgresql.Driver");
        Connection db = DriverManager.getConnection("jdbc:postgresql://localhost/racing/", "bzimmer", null);
        Statement c = db.createStatement();
        ResultSet rs = c.executeQuery("select * from bz");
    
        while (rs.next()) {
          List row = new ArrayList();
          ResultSetMetaData meta = rs.getMetaData();
          for(int i=0;i<meta.getColumnCount();i++) {
            int col = i+1;
            int datatype = meta.getColumnType(col);
            if (datatype == Types.INTEGER) {
              row.add(new Integer(rs.getInt(col)));
            } else if (datatype == Types.FLOAT) {
              row.add(new Float(rs.getFloat(col)));
            } else {
              row.add(rs.getString(col));
            }
          }
          System.out.println(row);
        }
        rs.close();
        c.close();
        db.close();
      }
    }

  • Python

    from java.sql import *
    from java.lang import *
    
    Class.forName("org.postgresql.Driver")
    
    db = DriverManager.getConnection("jdbc:postgresql://localhost/racing/", "bzimmer", None)
    c = db.createStatement()
    rs = c.executeQuery("select * from bz")
    
    _types = {Types.INTEGER:rs.getInt, Types.FLOAT:rs.getFloat}
    
    while rs.next():
      row = []
      meta = rs.getMetaData()
      for i in range(meta.getColumnCount()):
        col = i + 1
        datatype = meta.getColumnType(col)
        v = _types.get(datatype, rs.getString)(col)
        row.append(v)
      print tuple(row)
    rs.close()
    c.close()
    db.close()

  • zxJDBC

    from com.ziclix.python.sql import zxJDBC
    
    db = zxJDBC.connect("jdbc:postgresql://localhost/racing/", "bzimmer", None, "org.postgresql.Driver")
    c = db.cursor()
    c.execute("select * from bz")
    for row in c:
      print row
    c.close()
    db.close()

Examples - Embedding

  • Simple embedding example

    import org.python.core.PyObject;
    import org.python.core.PyInteger;
    import org.python.core.PyException;
    import org.python.util.PythonInterpreter;
    
    public class Embedded {
      public static void main(String []args) throws PyException {
        System.setProperty("python.home", "/Users/bzimmer/Development/sourceforge/jython");
    
        PythonInterpreter interp = new PythonInterpreter();
    
        System.out.println("Hello, brave new world");
        interp.exec("import sys");
        interp.exec("print sys");
    
        interp.set("a", new PyInteger(42));
        interp.exec("print a");
        interp.exec("x = 2+2");
        PyObject x = interp.get("x");
    
        System.out.println("x: "+x);
        System.out.println("Goodbye, cruel world");
      }
    }

  • More complicated example (included with Jython)

    package org.python.util;
    
    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import org.python.core.*;
    
    
    /**
     * This servlet is used to re-serve JPython servlets.  It stores
     * bytecode for JPython servlets and re-uses it if the underlying .py
     * file has not changed.
     * <p>
     * Many people have been involved with this class:
     * <ul>
     * <li>Chris Gokey
     * <li>David Syer
     * <li>Finn Bock
     * </ul>
     * If somebody is missing from this list, let us know.
     * <p>
     *
     * e.g. http://localhost:8080/test/hello.py
     * <pre>
     *
     * from javax.servlet.http import HttpServlet
     * class hello(HttpServlet):
     *     def doGet(self, req, res):
     *         res.setContentType("text/html");
     *         out = res.getOutputStream()
     *         print >>out, "<html>"
     *         print >>out, "<head><title>Hello World, How are we?</title></head>"
     *         print >>out, "<body>Hello World, how are we?"
     *         print >>out, "</body>"
     *         print >>out, "</html>"
     *         out.close()
     *         return
     * </pre>
     *
     * in web.xml for the PyServlet context:
     * <pre>
     * <web-app>
     *     <servlet>
     *         <servlet-name>PyServlet</servlet-name>
     *         <servlet-class>org.python.util.PyServlet</servlet-class>
     *         <init-param>
     *             <param-name>python.home</param-name>
     *             <param-value>/usr/home/jython-2.1</param-value>
     *         </init-param>
     *     </servlet>
     *     <servlet-mapping>
     *         <servlet-name>PyServlet</servlet-name>
     *         <url-pattern>*.py</url-pattern>
     *     </servlet-mapping>
     * </web-app>
     *
     * </pre>
     */
    
    public class PyServlet extends HttpServlet {
        private PythonInterpreter interp;
        private Hashtable cache = new Hashtable();
        private String rootPath;
    
    
        public void init() {
            rootPath = getServletContext().getRealPath("/");
            if (!rootPath.endsWith(File.separator))
                rootPath += File.separator;
    
            Properties props = new Properties();
    
            // Context parameters
            ServletContext context = getServletContext();
            Enumeration e = context.getInitParameterNames();
            while (e.hasMoreElements()) {
                String name = (String) e.nextElement();
                props.put(name, context.getInitParameter(name));
            }
    
            // Config parameters
            e = getInitParameterNames();
            while (e.hasMoreElements()) {
                String name = (String) e.nextElement();
                props.put(name, getInitParameter(name));
            }
    
            if (props.getProperty("python.home") == null &&
                                    System.getProperty("python.home") == null) {
                props.put("python.home", rootPath + "WEB-INF" +
                                                 File.separator + "lib");
            }
    
            PythonInterpreter.initialize(System.getProperties(), props,
                                         new String[0]);
            reset();
    
            PySystemState sys = Py.getSystemState();
            sys.add_package("javax.servlet");
            sys.add_package("javax.servlet.http");
            sys.add_package("javax.servlet.jsp");
            sys.add_package("javax.servlet.jsp.tagext");
    
            sys.add_classdir(rootPath + "WEB-INF" +
                              File.separator + "classes");
    
            sys.add_extdir(rootPath + "WEB-INF" + File.separator + "lib", true);
        }
    
        /**
         * Implementation of the HttpServlet main method.
         * @param req the request parameter.
         * @param res the response parameter.
         * @exception ServletException
         * @exception IOException
         */
        public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException
        {
            req.setAttribute("pyservlet", this);
    
            String spath = (String)req.getAttribute(
                                        "javax.servlet.include.servlet_path");
            if (spath == null) {
                spath = ((HttpServletRequest) req).getServletPath();
                if (spath == null || spath.length() == 0) {
                    // Servlet 2.1 puts the path of an extension-matched
                    // servlet in PathInfo.
                    spath = ((HttpServletRequest) req).getPathInfo();
                }
            }
            String rpath = getServletContext().getRealPath(spath);
    
            interp.set("__file__", rpath);
    
            HttpServlet servlet = getServlet(rpath);
            if (servlet !=  null)
                servlet.service(req, res);
            else
                throw new ServletException("No python servlet found at:" + spath);
        }
    
        public void reset() {
            destroyCache();
            interp = new PythonInterpreter(null, new PySystemState());
            cache.clear();
            PySystemState sys = Py.getSystemState();
            sys.path.append(new PyString(rootPath));
    
            String modulesDir = rootPath + "WEB-INF" +
                                File.separator + "jython";
            sys.path.append(new PyString(modulesDir));
        }
    
        private synchronized HttpServlet getServlet(String path)
            throws ServletException, IOException
        {
            CacheEntry entry = (CacheEntry) cache.get(path);
            if (entry == null)
                return loadServlet(path);
            File file = new File(path);
            if (file.lastModified() > entry.date)
                return loadServlet(path);
            return entry.servlet;
        }
    
        private HttpServlet loadServlet(String path)
            throws ServletException, IOException
        {
            HttpServlet servlet = null;
            File file = new File(path);
    
            // Extract servlet name from path (strip "…/" and ".py")
            int start = path.lastIndexOf(File.separator);
            if (start < 0)
                start = 0;
            else
                start++;
            int end = path.lastIndexOf('.');
            if ((end < 0) || (end <= start))
                end = path.length();
            String name = path.substring(start, end);
    
            try {
                interp.execfile(path);
                PyObject cls = interp.get(name);
                if (cls == null)
                    throw new ServletException("No callable (class or function) "+
                                           "named " + name + " in " + path);
    
                PyObject pyServlet = cls.__call__();
                Object o = pyServlet.__tojava__(HttpServlet.class);
                if (o == Py.NoConversion)
                    throw new ServletException("The value from " + name +
                                           "must extend HttpServlet");
                servlet = (HttpServlet)o;
                servlet.init(getServletConfig());
    
            } catch (PyException e) {
                throw new ServletException("Could not create "+
                                           "Jython servlet" + e.toString());
            }
            CacheEntry entry = new CacheEntry(servlet, file.lastModified());
            cache.put(path, entry);
            return servlet;
        }
    
        public void destroy() {
            destroyCache();
        }
    
        private void destroyCache() {
            for (Enumeration e = cache.elements(); e.hasMoreElements(); ) {
                CacheEntry entry = (CacheEntry) e.nextElement();
                entry.servlet.destroy();
            }
        }
    
    }
    
    class CacheEntry {
        public long date;
        public HttpServlet servlet;
    
        CacheEntry(HttpServlet servlet, long date) {
            this.servlet=  servlet;
            this.date = date;
        }
    }

Alternatives

  • Jython is not the only means for accessing Java libraries
  • Numerous other 100% Java language implementations
  • Several Python-Java integration efforts

Alternatives - 100% Java Languages

  • Groovy
    • Its a dynamically and/or statically typed language (i.e. static typing is optional, otherwise it defaults to dynamic typing) high level scripting language for the JVM which compiles down to bytecode either at run time or compile time. It features closures, neat List and Map syntax, integrated markup language and expression language, auto-boxing, operator overloading, mixins, AOP interceptors etc.
  • BeanShell
    • BeanShell is a small, free, embeddable, Java source interpreter with object scripting language features, written in Java. BeanShell executes standard Java statements and expressions, in addition to obvious scripting commands and syntax. BeanShell supports scripted objects as simple method closures like those in Perl and JavaScript(tm).
  • JRuby
    • A pure Java implementation of the Ruby interpreter
  • A much longer list

Alternatives - JVM-PVM Integration

  • Python
    • JPype
      • JPype is an effort to allow python programs full access to java class libraries. This is achieved not through re-implementing Python, as Jython/JPython has done, but rather through interfacing at the native level in both Virtual Machines.
      • Actively developed
    • JPE
      • JPE is a seamless, complete, and efficient integration of Java and standard Python (C Python).
      • Last cvs change in 2002
  • Independent compilation of Java
    • GCJ
      • GCJ is a portable, optimizing, ahead-of-time compiler for the Java Programming Language. It can compile:
        • Java source code directly to native machine code
        • Java source code to Java bytecode (class files)
        • Java bytecode to native machine code.
    • Java -> compiled library; compiled library -> SWIG; SWIG + Python
    • Actively developed

Alternatives - Distributed Objects

  • Pickling
    • CPython and Jython pickles are generally compatible
  • Pyro
    • Supports CPython-Jython communication
  • SOAP
  • CORBA

Alternatives - Which To Choose?

  • Depends of course
  • If 100% Java is important choose one of those.
  • Which platform will see the most development?

Performance

  • Java VM startup time does not rival CPython’s
  • JVM ships with JIT; Python requires seperate download of Psyco (not available for OS X)
  • Language backgrounds dictate where performance gains are realized
    • Python’s scripting background addresses startup, file iteration
    • Java focuses primarily on server processes with many threads
  • Some optimizations
    • PyIntegers cached

Performance - Startup

  • startup.py
    import sys
    print sys.version
    raise SystemExit()
  • Python
    $ time python startup.py
    2.3 (#1, Sep 13 2003, 00:49:11) 
    [GCC 3.3 20030304 (Apple Computer, Inc. build 1495)]
    
    real    0m0.147s
    user    0m0.010s
    sys     0m0.030s
  • Jython
    $ time jython startup.py
    2.2a0
    
    real    0m2.578s
    user    0m1.430s
    sys     0m0.250s

Performance - Iterate A File & Regular Expressions

  • ex_re.py
    import re
    import time
    
    s = time.time()
    c = re.compile("Slide.*-.*")
    for i in range(3):
      n = 0
      fp = open("jython-presentation.py", "r")
      try:
        for line in fp:
          if c.search(line):
            n += 1
      finally:
        fp.close()
      print "found %02d occurences" % (n)
    e = time.time()
    print e - s
    Something to note, files are not automatically closed in Jython as they are in CPython.
  • Python
    $ python ex_re.py 
    found 14 occurences
    found 14 occurences
    found 14 occurences
    0.0106308460236
  • Jython
    $ jython ex_re.py 
    found 14 occurences
    found 14 occurences
    found 14 occurences
    0.29399991035461426

Getting Starting

  • Download from http://www.jython.org
    • Only version ~2.1 available
  • Check out the current CVS head
    • Uses CPython 2.2 Lib/
  • Getting started documentation available on the site
  • The mailing lists have active support from numerous individuals

Development Environment

  • vim or SubEthaEdit for Python
  • Eclipse or IntelliJ for Java
  • ant for builds
    • No support for distutils setup.py building Java source
    • should be doable though
  • Any OS with JVM support

How It Works

  • Writing extension modules
  • Looking at the runtime through byte code

How It Works - Writing Extension Modules

  • Subclass PyObject
    • Remember, Java has single implemenation inheritance (but multiple interface inheritance)
  • If implementing a module, add to org.python.modules.Setup
    • This might change
  • Java<=>Python datatype mapping in both directions
    • This is not really extensible right now unless you implement the class yourself.
  • Sample code
     public void __setattr__(String name, PyObject value) {
    
       if ("arraysize".equals(name)) {
         this.arraysize = value.__int__().getValue();
       } else if ("softspace".equals(name)) {
         this.softspace = value.__int__().getValue();
       } else if ("datahandler".equals(name)) {
         this.datahandler = (DataHandler)value.__tojava__(DataHandler.class);
       } else {
         super.__setattr__(name, value);
       }
     }
    
     /**
      * Gets the value of the attribute name.
      *
      * @param name
      * @return the attribute for the given name
      */
     public PyObject __findattr__(String name) {
    
       if ("arraysize".equals(name)) {
         return Py.newInteger(arraysize);
       } else if ("softspace".equals(name)) {
         return Py.newInteger(softspace);
       } else if ("__methods__".equals(name)) {
         return __methods__;
       } else if ("__members__".equals(name)) {
         return __members__;
       } else if ("description".equals(name)) {
         return this.fetch.description;
       } else if ("rowcount".equals(name)) {
         return Py.newInteger(this.fetch.rowcount);
       } else if ("rownumber".equals(name)) {
         int rn = this.fetch.rownumber;
         return (rn < 0) ? Py.None : Py.newInteger(rn);
       } else if ("warnings".equals(name)) {
         return warnings;
       } else if ("lastrowid".equals(name)) {
         return lastrowid;
       } else if ("updatecount".equals(name)) {
         return updatecount;
       } else if ("datahandler".equals(name)) {
         return Py.java2py(this.datahandler);
       } else if ("dynamic".equals(name)) {
         return this.dynamicFetch ? Py.One : Py.Zero;
       } else if ("connection".equals(name)) {
         return this.connection;
       } else if ("closed".equals(name)) {
         return Py.newBoolean(closed);
       } else if ("callproc".equals(name)) {
         try {
           // dynamically decide on the the attribute based on the driver
           if (!getMetaData().supportsStoredProcedures()) {
               return null;
           }
         } catch (Throwable t) {}
       }
    
       return super.__findattr__(name);
     }
    
    /**
      * Returns an iteratable object.
      *
      * @return PyObject
      *
      * @since Jython 2.2, DB API 2.0+
      */
     public PyObject __iter__() {
       return this;
     }
    
     /**
      * Returns the next row from the currently executing SQL statement
      * using the same semantics as .fetchone().  A StopIteration
      * exception is raised when the result set is exhausted for Python
      * versions 2.2 and later.
      *
      * @return PyObject
      *
      * @since Jython 2.2, DB API 2.0+
      */
     public PyObject next() {
       PyObject row = __iternext__();
       if (row == null) {
         throw Py.StopIteration("");
       }
       return row;
     }
    
     /**
      * Return the next element of the sequence that this is an iterator
      * for. Returns null when the end of the sequence is reached.
      *
      * @since Jython 2.2
      *
      * @return PyObject
      */
     public PyObject __iternext__() {
       PyObject row = fetchone();
       return row.__nonzero__() ? row : null;
     }

How It Works - Writing Extension Modules - Thoughts

  • zxJDBC written as Java library
  • JNumeric uses primitivies for performance
  • Using Python is generally faster to implement
  • Wrap up Java-centric library with more Pythonic approach
  • PyObject subclassed object can grow dynamic attributes whereas Java instance cannot
  • The more Python modules converted to C make more work for Jython developers

How It Works - Runtime

Not my area of expertise — yet

  • First parsed by a JavaCC parser generated from grammar file
  • AST compiled to Java byte code
  • Extensive Java based runtime to support byte codes
  • Both JVM and PVM are stack-based virtual machines
  • Example python module
    a = 1 + 1
  • CPython bytecode
    1           0 LOAD_CONST               1 (1)
                3 LOAD_CONST               1 (1)
                6 BINARY_ADD
                7 STORE_FAST               0 (a)

How It Works - Runtime - Java

Remember, there is no operator overloading in Java

  • Java (using primitives)

    public class ExRuntime {
      public static void main(String[] args) {
        int a = 1 + 1;
      }
    }

  • Decompiled

    // Jad home page: http://www.geocities.com/kpdus/jad.html
    // Decompiler options: packimports(3) annotate 
    // Source File Name:   ExRuntime.java
    
    
    public class ExRuntime
    {
    
      public ExRuntime()
      {
      //    0    0:aload_0         
      //    1    1:invokespecial   #1   <Method void Object()>
      //    2    4:return          
      }
    
      public static void main(String args[])
      {
        byte byte0 = 2;
      //    0    0:iconst_2        
      //    1    1:istore_1        
      //    2    2:return          
      }
    }

  • Java (using Integers)

    public class ExRuntime2 {
      public static void main(String[] args) {
        int a = new Integer(1).intValue() + new Integer(1).intValue();
      }
    }

  • Decompiled

    // Jad home page: http://www.geocities.com/kpdus/jad.html
    // Decompiler options: packimports(3) annotate 
    // Source File Name:   ExRuntime2.java
    
    
    public class ExRuntime2
    {
    
      public ExRuntime2()
      {
      //    0    0:aload_0         
      //    1    1:invokespecial   #1   <Method void Object()>
      //    2    4:return          
      }
    
      public static void main(String args[])
      {
        int i = (new Integer(1)).intValue() + (new Integer(1)).intValue();
      //    0    0:new             #2   <Class Integer>
      //    1    3:dup             
      //    2    4:iconst_1        
      //    3    5:invokespecial   #3   <Method void Integer(int)>
      //    4    8:invokevirtual   #4   <Method int Integer.intValue()>
      //    5   11:new             #2   <Class Integer>
      //    6   14:dup             
      //    7   15:iconst_1        
      //    8   16:invokespecial   #3   <Method void Integer(int)>
      //    9   19:invokevirtual   #4   <Method int Integer.intValue()>
      //   10   22:iadd            
      //   11   23:istore_1        
      //   12   24:return          
      }
    }

How It Works - Runtime - Jython

  • Java source (using jython)

    // Jad home page: http://www.geocities.com/kpdus/jad.html
    // Decompiler options: packimports(3) 
    // Source File Name:   /home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py
    
    import org.python.core.*;
    
    public class e.PyObject extends PyFunctionTable
        implements PyRunnable
    {
    
        public PyObject f$0(PyFrame pyframe)
        {
            pyframe.setglobal("__file__", _0);
            pyframe.setline(1);
            PyObject pyobject = _1._add(_1);
            pyframe.setlocal("a", pyobject);
            pyobject = null;
            pyframe.f_lasti = -1;
            return Py.None;
        }
    
        public PyCode getMain()
        {
            return f$0;
        }
    
        public PyObject call_function(int i, PyFrame pyframe)
        {
            switch(i)
            {
            case 0: // '\0'
                return f$0(pyframe);
            }
            return null;
        }
    
        static final ng self;
        static final PyString _0 = Py.newString("/home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py");
        static final PyInteger _1 = Py.newInteger(1);
        static final PyCode f$0;
    
        static
        {
            self = new <init>();
            String as[];
            f$0 = Py.newCode(0, as = new String[0], "/home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py", "?", 0, false, false, self, 0, null, null, 0, 0);
        }
    
        public e.PyObject()
        {
        }
    }

  • Java bytecode source (using jython)

    // Jad home page: http://www.geocities.com/kpdus/jad.html
    // Decompiler options: packimports(3) disassembler 
    // Source File Name:   /home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py
    
    import org.python.core.*;
    
    public class e.PyObject extends PyFunctionTable
        implements PyRunnable
    {
    
        public PyObject f$0(PyFrame pyframe)
        {
        //    0    0:aload_1         
        //    1    1:ldc1            #11  <String "__file__">
        //    2    3:getstatic       #17  <Field PyString _0>
        //    3    6:invokevirtual   #9   <Method void PyFrame.setglobal(String, PyObject)>
        //    4    9:aload_1         
        //    5   10:iconst_1        
        //    6   11:invokevirtual   #22  <Method void PyFrame.setline(int)>
        //    7   14:getstatic       #26  <Field PyInteger _1>
        //    8   17:getstatic       #26  <Field PyInteger _1>
        //    9   20:invokevirtual   #32  <Method PyObject PyObject._add(PyObject)>
        //   10   23:astore_2        
        //   11   24:aload_1         
        //   12   25:ldc1            #34  <String "a">
        //   13   27:aload_2         
        //   14   28:invokevirtual   #37  <Method void PyFrame.setlocal(String, PyObject)>
        //   15   31:aconst_null     
        //   16   32:astore_2        
        //   17   33:aload_1         
        //   18   34:iconst_m1       
        //   19   35:putfield        #41  <Field int PyFrame.f_lasti>
        //   20   38:getstatic       #47  <Field PyObject Py.None>
        //   21   41:areturn         
        }
    
        public e.Py.None()
        {
        //    0    0:aload_0         
        //    1    1:invokespecial   #53  <Method void PyFunctionTable()>
        //    2    4:return          
        }
    
        public PyCode getMain()
        {
        //    0    0:getstatic       #58  <Field PyCode f$0>
        //    1    3:areturn         
        }
    
        static
        {
        //    0    0:new             #13  <Class ex_runtime$py>
        //    1    3:dup             
        //    2    4:invokespecial   #62  <Method void ex_runtime$py()>
        //    3    7:putstatic       #64  <Field ex_runtime$py self>
        //    4   10:ldc1            #66  <String "/home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py">
        //    5   12:invokestatic    #70  <Method PyString Py.newString(String)>
        //    6   15:putstatic       #17  <Field PyString _0>
        //    7   18:iconst_1        
        //    8   19:invokestatic    #74  <Method PyInteger Py.newInteger(int)>
        //    9   22:putstatic       #26  <Field PyInteger _1>
        //   10   25:iconst_0        
        //   11   26:iconst_0        
        //   12   27:anewarray       String[]
        //   13   30:astore_0        
        //   14   31:aload_0         
        //   15   32:ldc1            #66  <String "/home/bzimmer/development/ziclix/jython-presentation/ex_runtime.py">
        //   16   34:ldc1            #78  <String "?">
        //   17   36:iconst_0        
        //   18   37:iconst_0        
        //   19   38:iconst_0        
        //   20   39:getstatic       #64  <Field ex_runtime$py self>
        //   21   42:iconst_0        
        //   22   43:aconst_null     
        //   23   44:aconst_null     
        //   24   45:iconst_0        
        //   25   46:iconst_0        
        //   26   47:invokestatic    #82  <Method PyCode Py.newCode(int, String[], String, String, int, boolean, boolean, PyFunctionTable, int, String[], String[], int, int)>
        //   27   50:putstatic       #58  <Field PyCode f$0>
        //   28   53:return          
        }
    
        public PyObject call_function(int i, PyFrame pyframe)
        {
        //    0    0:iload_1         
        //    1    1:tableswitch     0 0: default 26
        //                   0 20
        //    2   20:aload_0         
        //    3   21:aload_2         
        //    4   22:invokevirtual   #86  <Method PyObject f$0(PyFrame)>
        //    5   25:areturn         
        //    6   26:aconst_null     
        //    7   27:areturn         
        }
    
        static final e.PyFrame self;
        static final PyString _0;
        static final PyInteger _1;
        static final PyCode f$0;
    }

Where Is Jython Going?

  • Better Java Integration
    • Drop JDK 1.1 support (to gain Collection framework support, simpler code, …)
      >>> from java.util import ArrayList
      >>> a = ArrayList([1,2,3])
      Traceback (innermost last):
        File "<console>", line 1, in ?
      TypeError: java.util.ArrayList(): 1st arg can't be coerced to java.util.Collection or int
  • Changes required for new Java 1.5 updates
    • enum
    • assert
  • Upgrade compatibility with Python 2.4
    • Currently uses CPython 2.2 Lib/
  • Implementation of new-style classes
    • Coming very soon
  • Implementation of popular missing modules
    • sets
    • select
    • datetime
  • Recently received one of three PSF grants for so development will continue

References

comments powered by Disqus

Recent Posts

About

I'm not here.