Python, Jython and Java
This tutorial is for Processing's Python Mode. If you see any errors or have comments, please let us know. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Processing.py is based on the Java implementation of Processing. It makes use of Jython, an implementation of Python that runs on the Java Virtual Machine (JVM), to directly access the underlying Java library. The benefit of this strategy is that your Processing.py sketches can do pretty much anything regular Processing sketches can do, and newer versions of Processing.py immediately benefit from performance enhancements and new features that are added to the Java implementation. When you're making sketches with Processing.py, you have access to best of three different software platforms and ecosystems: Python, Java, and Processing.
However, if you're already familar with any of these platforms, you may find that some things work in unintuitive way, or fail to work at all. This tutorial is designed to help you become literate about how Processing.py, Processing, Python and Java all work together, so you can reason better about how to diagnose problems and use the full potential of the platform.
Jython's limitations (and quirks)
Jython is an implementation of Python that runs on the Java Virtual Machine (JVM). Jython was initially developed as a way to write Python programs that make use of existing Java libraries, frameworks and infrastructure. Jython is designed to be as compatible as possible with all Python programs, and is generally just as fast as CPython (the "reference" implementation of Python, written in C) for most tasks.
However, Jython does have some significant limitations, especially if you're used to working with CPython. For more details, see the official Jython FAQ. But here's a rundown of the most important differences for users of Processing.py.
The latest version of Jython implements Python 2.7. Python 2.7 is still widely used, but Python 3 (which has a number of incompatibilities with earlier versions) is gaining popularity. If you're new to Python, keep in mind that some tutorials and example programs you find on the web will be written in Python 3, not Python 2.7, and may require a bit of reworking to make them functional in Processing.py.
Jython supports almost all of the Python standard library (i.e., the libraries that come with Python when you first install it). One notable exception is sqlite3 (although you can access SQLite databases using ODBC, and there's an open ticket for sqlite3 support in the Jython bug tracker. Jython does *not* support third-party Python libraries that use extensions written in C. This means that popular Python libraries like numpy, scipy and scikit-learn will not work in Jython (and, for this reason, will not work in Processing.py).
Unfortunately, there's no easy way to tell whether or not a library uses a C extension (or has a dependency on a library with a C extension) without attempting to install it, though there are some libraries that ship with a pure-Python fallback if it's impossible to compile the C extension.
Python and Java don't always see eye to eye
Java is a statically-typed language, whereas Python is dynamically typed. To make the two languages talk to each other, the implementors of Jython had to bridge the gap. This can occasionally result in unexpected problems when attempting to call Java code from Jython, or when attempting to write Jython code that can be called into from Java code.
One notable example is that classes in Jython are defined at runtime (unlike pure Java classes, which are usually defined at compile-time). This means that a number of features that are important for interoperability with Processing libraries, like method introspection, sometimes don't work as expected. The Jython and Java Integration chapter from The Jython Book has a number of good tips and tricks.
Gotchas for Python programmers
One of the goals of Processing.py is to follow the standard Processing API as closely as possible. This means that the functions you might call in "vanilla" Processing (i.e., the Java implementation) have exactly the same functionality in Processing.py.
There are, however, a number of Processing functions whose names conflict with existing built-in Python functions. To cope with these cases, Processing.py implements special "wrapper" functions invoke the appropriate underlying code based on the number of parameters passed to the call. Here's a list of some of the affected functions:
Processing.py makes the core Processing functions available by setting attributes of Jython's `__builtins__` object. If you're interested in the technical details, the built-ins are assigned in core.py, and the "wrapper" functions are implemented in PAppletJythonDriver.java.
Lists and arrays
To make things easier on beginner programmers, vanilla Java Processing includes a number of functions for easily manipulating arrays such as split(), splitTokens, append, arrayCopy, reverse, etc.). For compatibility purposes, Processing.py supports these functions, even though in most cases you would want to use Python built-in data structures instead.
If you do end up using these functions, be aware that they return Python array objects, not lists. (Jython internally represents Java arrays as objects of type array from Python's array module.) For example, consider the following two lines of code:
print type(split("a,b,c,d", ",")) # Processing built-in, prints
In most situations, arrays and lists are interchangeable, so you might not even notice. But arrays and lists have subtly different functionality, which might cause bugs in your program if you're not careful. For example, the following code raises a TypeError:
x = split("a,b,c,d", ",") x.append(20)
... because split() returns a strictly-typed array of Java String objects, and you can't append an integer to such an array. Likewise, lists and arrays don't compare element-wise, as illustrated by the following example:
x = split("a,b,c,d", ",") y = ["a", "b", "c", "d"] print x == y # prints False
Always keep an eye on the types of your variables and make sure you know what you're working with. In addition to the Processing functions mentioned above, there may be third-party libraries that you use in your Processing.py sketch that return array types as well. Fortunately, there's an easy fix: use the Python built-in list() function to convert the arrays into a list. For example:
x = list(split("a,b,c,d", ",")) y = ["a", "b", "c", "d"] print x == y # prints True
Note, however, that most vanilla Java Processing function that normally takes an array as a parameter will happily accept plain Python lists in their stead, though they'll still return an array. So, for example:
print shorten([1, 2, 3, 4]) # prints array('i', [1, 2, 3])
Gotchas for Java/Processing programmers
For various reasons, Processing.py's implementation of Processing functions differ in small ways from the implementation in vanilla Java Processing. For the most part, these differences will be invisible to you and the functions should "just work" as expected. Included below are a few quirks that might come up.
Using Processing Libraries
Most Processing libraries work with Processing.py out of the box. In Python Mode in the Processing IDE, you can search for and add libraries to your sketch using the "Add Tool..." dialog, just like you do with vanilla Java Processing. Processing.py adds a global variable this to your sketch automatically which you can pass to third-party libraries that need a reference to the current sketch.
Some Processing libraries want you to define functions in your sketch with particular names and signatures in your sketch as callbacks or event handlers. Right now, these libraries won't work in Processing.py unless specific support has been added. As of this writing, full or partial support exists for Serial, Video, Net and oscP5. If there's a library that you'd like to use that isn't yet supported, open an issue here.
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License