Jython : Java et Python
30/11/2006
JPython est né d’une volonté d’utiliser les technologies Java avec un langage simple et puissant : Python. L’interpréteur python a donc été réécrit en Java pour permettre le mélange entre les classes du jdk et l’intrépeteur python au sein de la même machine virtuelle Java. Suite à des problèmes de license déténue par le CNRI (qui a vu la naissance de Python et de JPython), un nouveau nom a été donné à ce projet : Jython.
Jython 2 est une version plus mature, qui subit un processus de développement plus intense que celui de JPython.
Jython permet de :
- compiler dynamiquement du python en bytecode Java
- hériter des classes Java en Jython
- compiler statiquement (création d’applets, servlets, beans…)
- utiliser la syntaxe et les modules python dans les programmes Java
- avoir un interpréteur python manipulant des objets Java
- Jython est certifié 100% Pure Java (portabilité assurée)
La procédure d’installation de Jython 2 n’a plus rien à voir avec celle de son ancêtre JPython 1.1. Elle est en effet vraiment trés simple. Pour ceux qui désirent travailler avec JPython 1.1, il faut non seulement installer JPython mais aussi l’errata de Finn Bock permettant de fixer pas mal de petites défaillances (voir liens). Cela dit, il n’y a pas vraiment de raison d’utiliser cette dernière, d’autant plus que la compatibilité ascendante est assurée.
Expérimentation de Jython
Voici un programme simple qui, décliné en plusieurs étapes permet de parcourir les possibilités d’utilisation du couple java/python. L’objet du programme est de retrouver des fichiers dans une arborescence, en utilisant les expressions régulières pour spécifier les noms de fichier.
Le moteur de recherche de ces fichiers est écrit en python, et cela pour :
- la faciliter d’écriture
- bénéficier de la puissance des expressions régulières, module fournit dans la distribution python
Par exemple, pour trouver les fichiers python contenant dans le nom ‘mllib’ et étant suffixés par ‘py’ ou ‘pyc’ contenus dans le répertoire lib de la distribution python, en utilisant l’interpréteur python :
Python 2.0 (#2, Oct 30 2000, 14:29:42) [GCC 2.8.1] on sunos5 Type "copyright", "credits" or "license" for more information. >>> import pyFind >>> finder=pyFind.FileFind() >>> finder.setPath("/users/public_w3p/share/python/Python-2.0/lib") >>> finder.setExprFile("[/].*?mllib[.](py|pyc)$") >>> finder.process() >>> for elem in finder.getFoundFiles(): ... print elem ... /users/public_w3p/share/python/Python-2.0/lib/python2.0/htmllib.py /users/public_w3p/share/python/Python-2.0/lib/python2.0/sgmllib.py /users/public_w3p/share/python/Python-2.0/lib/python2.0/xmllib.py /users/public_w3p/share/python/Python-2.0/lib/python2.0/htmllib.pyc /users/public_w3p/share/python/Python-2.0/lib/python2.0/sgmllib.pyc /users/public_w3p/share/python/Python-2.0/lib/python2.0/xmllib.pyc /users/public_w3p/share/python/Python-2.0/lib/python2.0/test/test_xmllib.py /users/public_w3p/share/python/Python-2.0/lib/python2.0/test/test_xmllib.pyc >>>
Une couche graphique
Pour rendre le moteur de recherche disponible de façon plus conviviale, une interface graphique est rajoutée. Pour cela, l’utilisation de Jython permet d’utiliser
- un composant python existant
- les librairies Java/Swing existantes
Jython sert alors de liant entre ces différentes technologies.
En plus de la présentation graphique, on peut rajouter la possibilité d’exécuter une action en double-cliquant sur un élément de la ul (classiquement une action d’édition ou de suppression).
Il y a trois (au moins) façons de réaliser ce programme. Les trois étapes décrites par la suite représentent une évolution du même programme depuis une approche 100% Java jusqu’à l’approche 100% Jython.
Pour chaque étape, le composant de recherche python décrit plus haut est utilisé, et :
- 100% du GUI en Java
- les composants graphiques adaptés de swing en Java, le modèle de données en Java, l’application graphique en Jython
- 100% du GUI en Jython
Etape 1 : Java utilise Python
Cet exemple illustre l’utilisation de l’interpréteur python au travers du code Java. Le but ici est d’utiliser le composant de recherche écrit en python dans du code Java. Le programme étant assez simple, voici un diagramme de classe :
Le package dont le rôle de contrôleur devrait faire l’interface entre les données, le graphique et l’interpréteur python, a été volontairement laissé de côté afin de réaliser un exemple court et fonctionnel. Il est à compléter.
- Main
- La classe Main représente juste le point de départ de l’application
- FindGui
- Le package contient la classe de l’interface graphique: une JFrame spécialisée. Elle recoit les évenements provenant de l’utilisateur, pilote l’interpréteur python, remplit le modèle de données, exécute ce qui doit l’être lors d’un double-clique (en somme GUI + contrôleur).
- FindData
- Le package contient la classe gérant les données issues de la recherche.
- SwingAdapter
- Le package contient les adaptations faites d’après Swing pour obtenir le rendu voulu. En particulier, la gestion du double-clique et la façon d’afficher chaque élément de la liste (en deux couleurs). Dans les autres exemples, tous ces services sont réalisés par du code Jython en utilisant la dérivation d’objets Java.
Le diagramme suivant représente l’organisation en terme de classes :
Utilisation de l’interpréteur
Pour utiliser le composant de recherche python défini dans le fichier (module) pyFind.py, et plus précisement la classe FileFind, il faut récupérer une instance de celle-ci.
Ceci se réalise par plusieurs étapes simples :
- importation du module
- La classe org.python.core.imp est utilisée pour réaliser l’importation du modulePyObject
findMod = imp.importName("pyFind", true);
- création d’une instance
- Une instance est créée (par réflexion) de la classe FileFind. Elle est représentée par un PyObject (org.python.core). C’est sur cette instance qu’il faut invoquer des méthodes.
PyObject findClass = findMod.__getattr__("FileFind"); findInstance = findClass.__call__();
- passage de paramètres, appel de méthodes
- Il suffit d’invoquer une méthode (premier argument) sur l’instance précédemment créée en passant les bons paramètres. Les types de base sont définis dans le package org.python.core. Une chaine de caractères passée comme paramètre est un PyString. Un entier est un PyInteger, un entier long un PyLong, etc…
PyObject res; // def setPath(self,p): res = findInstance.invoke("setPath",new PyString(whereText.getText())); // def setExprFile(self,r,simplified) res = findInstance.invoke("setExprFile",new PyString(whatText.getText())); // def process(self): res = findInstance.invoke("process");
- récupération du résultat
- Pour retrouver les différentes valeurs résultant de la recherche et stocker dans un tableau python, il suffit d’itérer sur cette liste et les insérer dans le modèle de données Java. Chaque élément est récupéré dans un PyObject, qui fournit la méthode toString.
PyObject item; for (int i = 0; (item = res.__finditem__(i)) != null; i++) { dataModel.addElement(item.toString()); }
Distribution
Les fichiers sont regroupés dans des archives, format zip et tarball. Les sources sont sous licence GPL. Le makefile fournit permet de compiler le code java et de lancer l’execution. Les possibilites sont compile,clean, exec. Le ‘make’ sans argument permet de tout enchainer.
make compile make exec ou make
Téléchargement :
Etape 2 : 50/50 Java/Jython
Cette étape permet d’écrire l’application graphique en Jython et non plus en Java. Il s’agit ici de modifier la classe FindGui sans pour autant changer tous les packages.
Le but est ainsi de démontrer qu’il est possible de créér une classe Python dérivant de classe(s) Java, soit par extension, soit par implémentation. Cette classe Python utilise alors des classes Java.
Migration vers Jython
La syntaxe Python étant plus simple et non typée, le code s’en trouve allégé (un des nombreux avantages du langage Python). Les principales différences sont évoquées ci dessous.
Le déclaration de la fenêtre principale devient :
class FindGui(JFrame, ActionListener):
à la place de :
public class FindGui extends JFrame implements ActionListener
La déclaration du constructeur (nommé __init__)
def __init__(self,title):
à la place de :
public FindGui(String title) {
A chaque déclaration d’une méthode Python, il faut passer comme premier argument l’objet lui même, celui ci est représenté par “self” (équivalent au “this” Java). Pour appeler le constructeur de la super classe, il faut explicitement le nommer comme n’importe quel autre appel :
JFrame.__init__(self,title, visible=1)
à la place de :
super(title);
En python, et à fortiori en Jython, les variables membres n’ont pas besoin d’être déclarées. Néanmoins, il est possible de le faire, tout dépend de la façon de programmer.
Les variables membres, au même titre que les méthodes, sont stockées dans un dictionnaire interne de la classe. Donc à chaque fois que l’on fait référence à un self.toto, si dans le dictionnaire, la clé ‘toto’ n’existe pas et qu’il s’agit d’une affectation, une nouvelle clé est insérée ainsi que la valeur associée. Si la valeur n’existe pas dans le dictionnaire et que l’on veut un accès en consultation, une exception est levée.
En prenant deux variables membres au hasard, l’une est déclarée dans le constructeur et affecté à rien (None), l’autre n’est déclarée que lors de l’instanciation du JButton.
self.foundlist = None self.searchButton = swing.JButton("Recherche")
En Java, il y a d’abord la déclaration, puis l’instanciation (bien que l’on puisse faire les temps en une seule étape) :
// déclaration private JList foundlist; private JButton searchButton; // création des objets foundlist = new JList(dataModel); searchButton = new JButton("Recherche");
Distribution
Les fichiers sont regroupés dans des archives au format tarball ou zip. Les sources sont sous licence GPL.
Le makefile fournit permet de compiler le code java, de créer un jar, et de lancer l’exécution. Les possibilités sont compile,jar,clean, et exec. Le ‘make’ sans argument permet de tout enchaîner.
Dans cette version, comme il y a du java à compiler, il faut mettre le bytecode dans un fichier jar pour que l’interpreteur jpython puisse trouver les classes.
make compile make jar make exec ou make
Téléchargement :
Etape 3 : Jython pilote java
Cette version est certainement une des plus intéresssantes, puisque l’ensemble du code écrit est du code Jython. Cela signifie que Jython est utilisé comme glue. Il permet de faire fonctionner les composants Java et/ou Python ensemble sans pour cela avoir besoin de créer un seul fichier à compiler. D’ailleurs, dans les sources, il n’existe plus de Makefile, seul l’interpréteur Jython est nécessaire.
Distribution
Les fichiers sont regroupés dans des archives au format tarball ou zip. Les sources sont sous licence GPL.
Pour lancer l’interface, il suffit de faire :
cd step3 jpython findgui.py
Téléchargement :