Jython is a Python interpreter which runs on top of Java. It provides the functionality of Python, plus a "pythonic" way to interact with existing Java APIs.
Consider initializing a Swing application in Jython. According to specifications, even constructing Swing components on the Main thread like this can be unsafe.
This code might seem OK, or it might crash intermittently and only on some platforms. The only way to conform to specifications is to move this initialization onto the event dispatch thread. The classic Java idiom to achieve this is to wrap the initialization code in a new subclass of Runnable, and pass this Runnable to the event dispatch thread to be executed. In Jython, this looks something like
from javax.swing import * jf = JFrame("Hi") jf.contentPane.add(JButton("does nothing")) # more unsafe initialization here # ... jf.pack() jf.visible = 1
This is a little verbose in Python, and would be significantly verbose in Java, to the point where programmers would prefer some sort of macro to simplify the process. The Python language feature of "decorators" provides this. In Python, decorators are functions which enhance or modify other functions. They are implemented as a Python function that accepts and returns functions as an argument. Here is a Python decorator that will transform any function into a version which is thread-safe for Swing:
from javax.swing import * from java.awt import EventQueue from java.lang import Runnable class initializeApp(Runnable): def run(self): global jf jf = JFrame("Hi") jf.contentPane.add(JButton("does nothing")) # more unsafe initialization here jf.pack() jf.visible = 1 EventQueue.invokeAndWait(initializeApp())
Using this decorator, we can do thread-safe Swing initialization succinctly
from java.awt import EventQueue from java.lang import Runnable def EDTsafe(function): def safe(*args,**kwargs): if EventQueue.isDispatchThread(): return function(*args,**kwargs) else: class foo(Runnable): def run(self): self.result = function(*args,**kwargs) f = foo() EventQueue.invokeAndWait(f) return f.result safe.__name__ = function.__name__ safe.__doc__ = function.__doc__ safe.__dict__.update(function.__dict__) return safe
There is also the option of using the decorator in one-line lambda functions, for example
from javax.swing import * @EDTsafe def initializeApp(): global jf jf = JFrame("Hi") jf.contentPane.add(JButton("does nothing")) # more unsafe initialization here jf.pack() jf.visible = 1 initializeApp()
EDTsafe( lambda: jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) )()