MokaByte 105 - Marzo 2006
 
MokaByte 105 - Marzo 2006 Prima pagina Cerca Home Page

 

 

 

Python e Java
Potenziare Java con un linguaggio di scripting

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, JButton
from java.lang import System

def 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, JButton
from java.lang import System

class Counter(object):

def __init__(self):
self.count = 0

def hello(self, e):
self.count += 1
print "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 = counter

def 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 ereditata da 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°.

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.

 

Riferimenti
[1] http://www.tcl.tk/doc/scripting.html
[2] http://www.python.org/
[3] http://www.jython.org/