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.
from javax.swing import *
jf = JFrame("Hi")
jf.contentPane.add(JButton("does nothing"))
# more unsafe initialization here
# ...
jf.pack()
jf.visible = 1
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 *
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())
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 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
Using this decorator, we can do thread-safe Swing initialization succinctly
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()
There is also the option of using the decorator in one-line lambda functions, for example
EDTsafe( lambda: jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) )()