Python e Java: potenziare Java con un linguaggio di scripting

di Leonardo Casinidi

I linguaggi di scripting sono spesso sottovalutati o considerati utili solo per piccoli progetti e situazioni usa-e-getta. In questo articolo vedremo invece come è possibile affiancare il linguaggio Python a Java per migliorare produttività ed estensibilità delle applicazioni.

Introduzione

In un celebre articolo [1] del 1998 John Ousterhout, il padre di Tcl, argomenta sulle differenze fra i linguaggi di sistema e quelli di scripting. I linguaggi di sistema come Java sono progettati per costruire algoritmi e strutture dati da zero, partendo da elementi primitivi come i byte di memoria. Al contrario i linguaggi di scripting sono intesi fondamentalmente come strumenti di integrazione che permettono di connettere fra loro componenti esistenti. Mentre i primi sono fortemente tipati per poter gestire la complessità , i secondi non lo sono per semplicare la connessione fra componenti e avere tempi di sviluppo rapidi.

In questa sede affronteremo l‘integrazione fra Java e Python [2], un linguaggio di scripting semplice, potente, orientato agli oggetti, dotato di una vastissima collezione di librerie e supportato da un‘attiva e numerosa comunità  di utenti. L‘integrazione è resa possibile dal progetto Jython [3], un‘implementazione completa e interamente Java del linguaggio Python. Nel seguito indicheremo con Python il linguaggio nella sua generalità , mentre con Jython intenderemo la particolare implementazione Java.

La distribuzione di Jython contiene, fra le altre, 3 parti fondamentali:

  • jython, l‘interprete Python;
  • jythonc, che compila programmi Python in classi Java;
  • jython.jar, la libreria per inglobare l‘interprete all‘intero di applicazioni Java

L‘integrazione può essere realizzata soprattutto in due modi: usando Python per scrivere il programma principale che utilizzi componenti scritte in Java; oppure integrando nel programma Java un interprete che esegua codice Python dall‘interno dell‘applicazione. Le due soluzioni hanno naturalmente ambiti d‘uso e scopi differenti.

Java dentro Python

Come accennato nell‘introduzione, il Python può essere utilizzato per fungere da "collante" fra varie componenti scritte in un linguaggio di sistema come Java. Si può quindi sviluppare un modello in Java, sfruttando tutti gli strumenti messi a disposizione dal linguaggio per ottenere strutture efficaci e robuste, e poi usarle all‘interno di un programma principale scritto in Python. Questo approccio è utile per esempio per sviluppare rapidamente prototipi, interfacce utente, test, ecc.

Jython permette oltretutto di importare le librerie Java ed utilizzarle (quasi) come librerie native. Come esempio vediamo un semplice programma che visualizza un‘interfaccia Swing con due bottoni.

from pawt.swing import JFrame, JPanel, JButtonfrom java.lang import Systemdef hello(e):print "Ciao, mondo!"def exit(e):System.exit(0)frame = JFrame(‘Esempio‘, visible=1)panel = JPanel()frame.contentPane.add(panel)helloButton = JButton(‘Ciao‘, actionPerformed=hello)panel.add(helloButton)exitButton = JButton(‘Esci‘, actionPerformed=exit)panel.add(exitButton)frame.pack()

Se il programma è stato salvato nel file hello.py, per eseguirlo basterà  invocare l‘interprete:

jython hello.py

Come si può notare la sintassi del Python è molto chiara e sintetica ed è possibile realizzare applicazioni utilizzando librerie Java e scrivendo poche righe di codice. In alcuni casi viene fornito da Jython un modulo wrapper intorno a particolari librerie; ad esempio pawt trova l‘ubicazione delle librerie Swing che, a seconda della distribuzione Java, possono trovarsi in package differenti come java.awt.swing, javax.swing, ecc.

Python è un linguaggio orientato agli oggetti, per cui gli sviluppatori Java si troveranno a loro agio potendo utilizzare un paradigma di programmazione a loro familiare. Rivediamo l‘esempio precedente aggiungendo una classe.

from pawt.swing import JFrame, JPanel, JButtonfrom java.lang import Systemclass Counter(object):def __init__(self):self.count = 0def hello(self, e):self.count += 1print "Ciao, mondo! (%d)" % (self.count,)def exit(self, e):print "Hai salutato %d volte." % (self.count,)System.exit(0)class Hello(JFrame):def __init__(self, counter, title=‘Esempio‘):JFrame.__init__(self, title, visible=1)self.counter = counterdef run(self):panel = JPanel()self.contentPane.add(panel)helloButton = JButton(‘Ciao‘, actionPerformed=self.counter.hello)panel.add(helloButton)exitButton = JButton(‘Esci‘, actionPerformed=self.counter.exit)panel.add(exitButton)self.pack()c = Counter()hello = Hello(c)hello.run()

In quest‘ultimo esempio abbiamo definito due classi, una addirittura ereditando una classe Java!

Python dentro Java

Un‘altra soluzione consiste nell‘inglobare (in gergo embed) l‘interprete nella nostra applicazione Java, cosଠche possa eseguire codice Python dall‘interno. Questo approccio permette, per esempio, di implementare per le nostre applicazioni un‘architettura a plugin che preveda una parte centrale in Java che svolga le elaborazioni principali e delle parti periferiche che estendano le funzionalità  dell‘applicazione in modo autonomo. La parte centrale (o framework) fornisce dei punti di inserimento per le parti periferiche (plugin) e comunica con esse. I plugin ricevono informazioni dal framework e le elaborano in maniera autonoma ed indipendente.

Una simile architettura permette di estendere rapidamente le funzionalità  dell‘applicazione, senza modificarne in alcun modo la struttura o conoscerne i dettagli interni, e permette una maggiore flessibilità  nella scelta delle funzionalità  da distribuire, per esempio in installazioni diverse.

Benchà© i plugin possano essere scritti in Java, la scelta di un linguaggio di scripting come il Python ha alcuni vantaggi:

  • consente una maggiore rapidità  di sviluppo;
  • consente la scrittura di plugin anche a chi non conosce Java (imparare il Python è più facile);
  • consente l‘accesso alle numerose e variegate librerie Python in aggiunta a quelle Java.

Vediamo un semplice esempio di embedding. Simuliamo un sistema Java che acquisisce la temperatura di una vasca d‘acqua attraverso un sensore. Vogliamo che sia possibile estendere questo sistema con uno script Python in modo che si possano eseguire delle azioni ogni volta che viene acquisita la temperatura, per esempio una scritta d‘avvertimento quando la temperatura dell‘acqua scende sotto i 37 °C.

import java.util.Timer;import java.util.TimerTask;import org.python.util.PythonInterpreter;public class Vasca extends TimerTask {private final PythonInterpreter interpreter;public Vasca() {interpreter = new PythonInterpreter();}public void run() {Double val = new Double(((Math.random() * 5) + 1) + 35);interpreter.set("t", val);interpreter.execfile("script.py");}public static void main(String[] args) {Vasca vasca = new Vasca();Timer timer = new Timer();timer.schedule(vasca, 0, 1000);}}

Il simulatore non fa altro che emettere un numero casuale ogni secondo; inoltre contiene un interprete Python a cui viene passato il numero generato e quindi eseguito uno script presente sul filesystem:

interpreter.set("t", val);interpreter.execfile("script.py");

Il metodo set() passa all‘interprete l‘oggetto val con il nome t: da quel momento l‘ambiente Python conterrà  una variabile t con il numero generato. Il metodo execfile() invece esegue nell‘ambiente Python il codice contenuto nel file script.py; il file, per essere correttamente localizzato, dovrà  trovarsi nel classpath. Lo script può essere qualcosa di simile a questo:

# avverti se la temperatura scende sotto i 37°if t<37:print "temperatura: %2.2f°" % (t,)print "attenzione!"

Dopo una prima riga di commento, lo script verifica che la temperatura non scenda sotto 37°, altrimenti stampa la temperatura e l‘avvertimento.

Conclusioni

La potenza e la flessibilità  dei linguaggi di scripting sono spesso sottovaluate, cosଠcome spesso non sono ben comprese le differenze con i linguaggi di sistemi. L‘introduzione di linguaggi di scripting nei processi di sviluppo può portare numerosi benefici, in termini di qualità  del codice, chiarezza e tempi di sviluppo. Inoltre è notevole la duttilità  di questi strumenti, che come abbiamo visto possono interfacciarsi ai linguaggi di sistema con modalità  diverse a seconda delle esigenze che si presentano.

1http://www.tcl.tk/doc/scripting.html2http://www.tcl.tk/doc/scripting.html

Condividi

Pubblicato nel numero
105 marzo 2006
Ti potrebbe interessare anche