- presentazione del sito
- Registrazione
- Eventi, mostre, convegni ed iniziative segnalate dalle aziende
- Recensioni ed articoli
- Le Mailing Lists
- La rivista Pc Ciechi
- Wiki
- Chi siamo
- Donazioni
- Un progetto degno di nota: Wintalbra
- Come navigare in questo sito
- rss
- Bancomat Accessibili sul territorio nazionale
- Contattaci
- I sostenitori di SpazioAusili
uno sguardo al python, seconda parte.
donato taddei in privato, 05\02\2008, h. 23.50.
Nota.
Ed ora, un po' di pubblicità
:A scanso di confusioni si precisa che l'autore di questo testo ha adottato la seguente convenzione, che quindi vale anche per la prima parte:
le righe contrassegnate da ">>>" rappresentano ciò che viene immesso al prompt di python;
le righe che iniziano con scritte racchiuse tra parentesi angolari "<...>" rappresentano invece la risposta dell'interprete a tali comandi, non hanno cioè
niente a che vedere con la sintassi del python.
In questa seconda parte vengono illustrati concetti riguardo ai cosiddetti moduli e sono di grande importanza per comprendere il significato dei più di
venti moduli presenti nel pacchetto nvda, segnatamente nelle cartelle appmodule e synthdrivers.
Affronta altresì uno degli agmenti più indigesti degli attuali ambienti di programmazione, a prescindere dal linguaggio:
moduli, oggetti, classi, ereditarietà sui quali sarà necessario tornare in seguito, con qualche noterella sulla loro storia evolutiva.
Per ora, e sempre a scanso di equivoci e confusioni, mi limiterò a una disambiguazione semantica:
programmazione ad oggetti e programmazione orientata agli oggetti, nel senso in cui sono normamente utilizzati, sottengono concetti non completamente sovrapponibili:
i programmatori di applicazioni windows chiamano oggetti qualsiasi cosa: finestgre, caselle, elementi grafici ecc.
Nvda per esempio chiama navigatore ad oggetti il dispositivo con cui più o meno esplora le applicazioni sullo schermo.
Sarebbe forse pù esatto chiamarli risorse.
Anche la programmazione windows conosce e manipola oggetti in senso proprio:
le interfacce ole, con cui ad esempio si gestisce da programma un foglio di excels una pagina web o un documento di word sono appunto degli oggetti in senso
proprio.
Dunque Guido Ruggeri usa massicciamente oggetti nel suo winguido.
Cose come direcrt x, e gli altri sistemi di script che windows mette a disposizione (wscript ecc.) manipolano oggetti in senso proprio.
Java, perl, pytho, e il loro fratello maggiore c++ sono linguaggi che sono stati inventati appunto per manipolare oggetti.
Da quanto apppreso in questo testo e affini letti ultimamente devo convenire che tra a questi linguaggi sicuramente il python è quello con la sintassi più
semplice.
Posso infatti confermare per esperienza diretta che la gestione degli oggetti in perl è sicuramente più astrusa, tant'é che ho fin qui evitato quando possibile
di utilizzarli.
Donato Taddei
.
Uno sguardo al Python - parte seconda
In questo articolo completiamo il discorso introduttivo al Python
esaminandone le caratteristiche più avanzate: classi, ereditarietà ed
eccezioni. Vedremo che il linguaggio utilizza un modello di OOP molto
semplice ma potente, che supporta ereditarietà multipla e operator
overloading.
Uno sguardo al Python
parte seconda
di Michele Sciabarrà
Se l'introduzione di Python della volta scorsa vi è parso interessante,
questa seconda parte è una buona occasione per approfondirlo. Ovviamente
non abbiamo alcuna pretesa di essere esaustivi, non potendo trattare un
completo linguaggio di programmazione in 10 pagine, esempi compresi.
Tuttavia questi due articoli dovrebbero essere sufficienti a muovere i
primi passi e decidere se vale la pena continuare. Entriamo subito nel
vivo esaminando le caratteristiche un po' più avanzate concernenti
programmazione ad oggetti e la gestione degli errori. Vedremo infatti che
Python pur nella sua grande semplicità è orientato ad oggetti in maniera
così decisa che è stato proposto come linguaggio standard per lo scripting
di oggetti distribuiti CORBA.
Istanze
Abbiamo visto i moduli, ovvero file che contengono definizioni di funzioni
e altri comandi. Creando un nuovo file, chiamato per esempio modulo.py,
contenente la definizione di funzione f(), è possibile importarlo con
import modulo per poi chiamare la funzione f usando la sintassi
modulo.f(). Per inciso, il file è importabile se la directory che lo
contiene si trova nel PYTHONPATH. L'impostazione del PYTHONPATH varia da
sistema a sistema, ma generalmente si tratta di impostare la variabile di
ambiente PYTHONPATH. Notare che f in questo caso è una funzione, non un
metodo o altro, anche se per accedervi occorre utilizzare il prefisso
modulo. Un modulo è infatti un esempio di namespace; gli elementi in un
namespace sono detti attributi. Per accedere ad un elemento di un
namespace si utilizza la sintassi namespace.attributo. I builtin (per
esempio dir) si trovano nel namespace __builtins__., e sono accedibili
(come caso particolare) anche se non si specifica un prefisso. Un altro
modo per evitare il prefisso è utilizzare from import
, ma è meglio non abusare di questa facility per non avere
problemi di collisioni di nomi.
Le istanze delle classi sono anche essi dei namespace, anche se si
comportano in maniera più sofisticata dei moduli. Si tratta in un certo
senso della naturale evoluzione della programmazione modulare verso la
programmazione ad oggetti. Nel resto dell'articolo si assumono basi di
OOP: non spiegheremo che cosa è una classe, una istanza, un costruttore o
una funzione virtuale, per cui se siete a digiuni di queste nozioni
potreste incontrare qualche difficoltà nella lettura.
Abbiamo visto che in Python ci sono svariati tipi di dato, come le
sequenze, i dizionari, e i moduli. Adesso introdurremo un nuovo tipo di
dato, ovvero la classe. Prima vediamo come si usano le classi esistenti,
poi esamineremo come si definiscono nuove classi. Sfruttiamo l'aspetto
interattivo del Python, che ci consente di imparare cose nuove
sperimentando con l'interprete a riga di comando. Come esperimento per
imparare l'uso di oggetti preleveremo ed esamineremo una pagina Web con
una connessione http, usando la classe HTTP del modulo httplib:
>>> import httplib
>>> httplib.HTTP
>>> h = httplib.HTTP("192.168.1.1")
>>> h
Innanzitutto notiamo che le classi, come le funzioni, sono contenute
dentro moduli. In particolare la classe HTTP è contenuta nel modulo
httplib, per cui occorre importare il modulo (altrimenti tale classe non è
accessibile). Valutando httplib.HTTP osserviamo che si tratta di un
oggetto di tipo classe, utilizzabile però in maniera analoga ad una
funzione. Chiamando la classe, otteniamo un oggetto di tipo istanza della
classe, come si vede nell'esempio. In pratica la classe è una funzione
costruttore che produce istanze. L'oggetto istanza così costruito si
comporta in maniera simile ad un modulo, ovvero come contenitore di
funzioni che possono essere chiamate. In realtà un oggetto è qualcosa di
più di un modulo, in quanto mantiene uno stato separato per ogni istanza.
Quindi la classe è la naturale evoluzione del concetto di modulo: un
oggetto è un namespace analogamente ad un modulo. La differenza principale
è che si possono creare istanze diverse dello stesso modulo, ottenendo
namespace separati con variabili indipendenti. Questo è il punto cruciale.
I dati contenuti in una istanza di una classe vengono inizializzati
chiamando una particolare funzione di inizializzazione: __init__. L'ultimo
elemento importante che differenzia le classi dai moduli è il fatto che su
di esse si può applicare l'ereditarietà, come vedremo più avanti.
Riassumendo:
Namespace: spazio di nomi, contenente attribuiti; agli attributi di un
namespace si accede con la sintassi namespace.attributo.
Modulo: namespace, che contiene funzioni e altri elementi, letto da un
file.
Classe: una funzione in grado di generare istanze, ovvero un
costruttore.
Istanza: namespace che contiene funzioni dette metodi; l'istanza
differisce dal modulo per il fatto che viene creata dinamicamente
(mentre i moduli sono definiti con dei file) e che gli attributi sono
indipendenti per ogni istanza, anche se l'istanza viene creata dallo
stesso costruttore.
Metodo: funzione appartenente ad una classe, che solitamente modifica le
variabili dell'istanza a cui appartiene (in altre parole cambia lo stato
dell'oggetto).
Torniamo al nostro esempio, e utilizzando l'istanza di HTTP chiamandone i
metodi:
>>> h.putrequest('GET', '/')
>>> h.endheaders()
>>> h.getreply()
(200, 'OK', )
>>> f = h.getfile()
>>> lines = f.readlines()
>>> lines[0]
'\012'
Di ogni oggetto, per usarlo occorre conoscerne il funzionamento leggendone
la documentazione. Nel caso che stiamo esaminando adesso, una istanza di
HTTP invia delle richieste corrispondenti ai comandi HTTP. Questa classe
in realtà non maschera molto il protocollo http, in quanto occorre
conoscerlo almeno per sommi capi. In particolare, occorre sapere che la
richiesta per prelevare una pagina web è GET, seguita dall'URL della
pagina senza l'indirizzo dell'host. Dopo la richiesta, occorre anche
aggiungere delle informazioni supplementari che vengono date al Web Server
utilizzando degli header. Nel nostro caso non inviamo alcuna informazione
supplementare, completando la richiesta con endheader(), e leggiamo la
risposta del Web Server. Poiché è OK (codice 200, stringa di messaggio OK,
altre informazioni nella istanza mimetools.Message) possiamo leggere la
pagina web tramite un oggetto file per la lettura. Per semplicità,
leggiamo le righe ponendole in una lista, e ne stampiamo solo la prima.
Classi
Impariamo adesso a creare nuove classi. Nel caso più semplice possiamo
dichiarare una classe vuota:
>>> class Void:
... pass
...
>>> x = Void()
>>> x
<__main__.Void instance at 85ff80>
>>> x.a
Traceback (innermost last):
File "", line 0, in ?
AttributeError: a
>>> x.a=1
>>> y = Void()
>>> y.a=2
>>> print x.a,y.a
1 2
Utilizzando la keyword class abbiamo dichiarato una nuova classe, in
questo chiamata Void. In una definizione di classe possono esserci comandi
di qualsiasi genere, che vengono eseguiti durante la definizione della
classe. I comandi per noi interessanti comunque sono quelli che dichiarano
attributi, ovvero variabili e funzioni che diventano campi e metodi della
classe. Gli altri comandi possono servire per esempio a definire dei
metodi condizionalmente (per esempio in un modo sotto Windows e un altro
sotto Unix) ma è meglio non abusare di queste possibilità.
Ad una classe non vengono assegnati una volta e per tutte tutti i suoi
attributi, ma possono essere aggiunti anche dopo che l'istanza è stata
creata. Infatti in genere gli attributi vengono aggiunti in fase di
inizializzazione. Come si vede nel'esempio, dopo aver dichiarato la
classe, utilizziamo la funzione costruttore, avente lo stesso nome della
classe, per creare nuove istanze. Nell'esempio utilizzando Void come
funzione abbiamo creato l'istanza. Ogni instanza è un namespace separato
che inizialmente non contiene alcun attributo. La natura dinamica del
Python ci consente di aggiungere, "al volo", nuovi attribuiti,
nell'esempio a. Che le istanze siano namespace separati e indipendenti si
vede anche dal fatto che creando due istanze, possiamo assegnare ad ogni
istanza un valore diverso per l'attribuito a. Otteniamo, come ci si
aspetta, due a separati e indipendenti per ogni istanza.
Listato 1
class List:
def __init__(self, data, next=None):
self.data=data
self.next=next
def append(self, data):
curr = self
while not curr.next is None:
curr = curr.next
curr.next = List(data)
return self
def push(self, data):
return List(data,self)
def printall(self):
while not self is None:
print self.data
self=self.next
Le classi divengono interessanti quando contengono campi e metodi. Nel
Listato 1 possiamo vedere la dichiarazione di una classe List, contenuta
nel file list.py, che andiamo subito ad utilizzare:
>>> import list
>>> x = list.List(2)
>>> x.printall
>>> x.printall()
2
>>> x = x.push(1)
>>> x.printall()
1
2
>>> x=x.append(3)
>>> x.printall()
1
2
3
Come si vede, abbiamo definito una classe lista con tre metodi: append,
push e printall. Esaminiamo ora in dettaglio il meccanismo della
definizione della classe. Dichiarando una classe ci ritroviamo con una
funzione costruttore che ha lo stesso nome della classe. In realtà questo
costruttore crea soltanto l'oggetto istanza, ma non lo inizializza. Se
occorre effettuare delle inizializzazioni supplementari (caso abbastanza
frequente), si deve definire una funzione di inizializzazione che si deve
chiamare __init__. L'uso dei doppi underscore all'inizio e alla fine è una
convenzione Python usata ovunque sia necessario definire nomi che hanno un
significato speciale, e non è limitata solo a questo caso. La __init__
viene chiamata automaticamente dopo che è stata creata l'istanza
dell'oggetto.
Veniamo ora a quello che è un punto critico, ed è basilare per comprendere
tutto il meccanismo della OOP in Python. Dovrebbe essere chiaro come
funzionano in Python le funzioni (non c'è niente di speciale, a parte il
fatto che sono solitamente contenute dentro dei moduli). Ora, nelle classi
non ci sono funzioni ma metodi. In OOP, in generale i metodi sono funzioni
speciali, in quanto conoscono l'oggetto a cui appartengono. In Java, C++ e
altri linguaggi OOP l'accesso all'oggetto corrente è implicito e nascosto:
il programmatore non se ne accorge. In Python invece l'oggetto corrente
viene passato esplicitamente come primo parametro della chiamata del
metodo. Confrontando l'ultimo esempio con il listato il meccanismo
dovrebbe diventare abbastanza chiaro. Precisamente, scrivendo x =
list.List(2) si costruisce un oggetto istanza, poi viene chiamato
automaticamente __init__(self, data, next=None). Il primo parametro di
__init__ è l'oggetto appena costruito, il secondo è il parametro fornito
al costruttore (2). In questo esempio si utilizza anche la feature dei
parametri di default: poiché non abbiamo specificato il terzo parametro
questo assume il valore di default None. Il meccanismo è analogo quando
invochiamo i metodi: chiamato x.printall() viene chiamata la funzione
printall passando x come primo parametro. Per convenzione il primo
parametro di un metodo viene chiamato self. Non c'è niente di speciale in
questo nome ma non seguire questa convenzione può compromettere la
leggibilità del vostro listato ad altri programmatori Python. Non ci sono
modi per accedere direttamente ai campi di un oggetto: occorre usare
sempre il prefisso self. Per quanto questa cosa possa apparire noiosa, in
pratica questo migliora la leggibilità e evita ambiguità con le variabili
locali.
Ereditarietà
L'ereditarietà è il meccanismo che consente di riutilizzare codice già
esistente organizzato in classi: grazie ad essa possiamo creare nuove
classi che estendono e modificano quelle esistenti. Esemplifichiamo il
funzionamento, considerando una classe Punto2D, che estendiamo per
ottenere un Punto3D:
import math
class Punto2D:
def __init__(self, x, y):
self.x = x
self.y = y
def dist(self):
return math.sqrt(self.x **2 + self.y **2)
class Punto3D(Punto2D):
def __init__(self, x, y, z):
Punto2D.__init__(self, x, y)
self.z = z
def dist(self):
return math.sqrt(Punto2D.dist(self)**2 + self.z**2)
Per ereditare da una classe si usa la sintassi class
Derivata(Base1,Base2), dove Derivata è la classe che eredita dalle classi
Base1 , Base2. Nell'esempio di sopra è mostrato un caso di ereditarietà
singola ma Python supporta in generale l'ereditarietà multipla. La nuova
classe eredita tutti i metodi delle classi base, il che significa che un
metodo disponibile in una Base1 o Base2 è disponibile anche nella classe
Derivata. Un metodo può trovarsi anche in più di una delle classi base: in
tal caso viene usato il metodo trovato effettuando una ricerca deep-first
nel grafo delle classi.
La cosa importante è che ereditando possiamo ridefinire i metodi della
classe base, come si vede nell'esempio, dove il metodo dist di Punto3D
ridefinisce il metodo dist di Punto2D. Per accedere ai metodi della classe
base (operazione necessaria per sfruttare il codice preesistente) si deve
far riferimento esplicitamente al metodo chiamandolo con il nome della
classe e passando self come parametro. Nell'esempio si nota come vengano
chiamati esplicitamente Punto2D.dist e Punto2D.__init__. Infine accenniamo
al fatto che Python supporta anche l'operator overloading: è possibile per
esempio ridefinire l'operatore + definendo il metodo __sum__, l'operatore
* ridefinendo il metodo __mult__ e così via. Non trattiamo in dettaglio
queste caratteristiche per ragioni di spazio.
Eccezioni
Durante l'esecuzione dei programmi possono insorgere degli errori.
Linguaggi tradizionali come il C o il Pascal non prendono particolari
provvedimenti per gestirli (è compito del programmatore "stare attento" e
verificare bene i valori ritornati per riconoscere e gestire gli errori).
In pratica però una condizione di errore è sempre qualcosa di particolare
che altera il normale flusso del programma, e che tende a sfuggire
all'attenzione del programmatore. Queste condizioni eccezionali, in
pratica così eccezionali non sono, e devono essere in qualche modo gestite
perché i programmi diventino robusti (ovvero non si piantano ogni 5
minuti). Non a caso i "disastri a catena" che avvengono nei programmi
hanno origine in qualche errore non gestito che si propaga causando errori
su errori fino alla terminazione del programma (nei casi fortunati) o il
blocco del sistema (di solito). Per gestire le condizioni di errore è
stato inventato, fin dai tempi antichi dell'informatica (vent'anni fa), il
meccanismo delle eccezioni. Per molto tempo però la gestione delle
eccezioni è rimasta confinata ai linguaggi assembler: da qualche anno è
approdata anche ai linguaggi ad alto livello, come C++, Java e, appunto,
Python.
Vediamo come funzionano le eccezioni considerando la gestione di un errore
tanto semplice quanto (spesso) inaspettato: una divisione per zero:
>>> x = 0
>>>
>>> 1/x
Traceback (innermost last):
File "", line 0, in ?
ZeroDivisionError: integer division or modulo
>>> try:
... y = 1/x
... except ZeroDivisionError:
... print "cannot divide!"
...
cannot divide!
>>> ZeroDivisionError
In caso di eccezione, l'esecuzione si interrompe e causa la stampa di un
messaggio di errore. Per essere esatti, durante l'esecuzione di un
programma una eccezione causa il ritorno dalla funzione o metodo in cui ci
si trova e la generazione di un eccezione nel punto in cui si ritorna.
Questo meccanismo viene ripetuto, portando ad un ritorno forzato da tutte
le chiamate correnti finché non si raggiunge il toplevel (che causa la
terminazione con un messaggio errore), a meno che l'eccezione non venga in
qualche modo catturata e gestita. In questo modo le condizioni di errore
non sono ignorabili a meno che il programmatore non decida esplicitamente
di ignorarle. Comunque in questo mod si tende a confinare gli errori in
precisi sottosistemi che non causano la terminazione anomala del
programma. Nell'esempio vediamo anche come funziona il meccanismo di
gestione delle eccezioni: si sottopone a controllo il blocco che può
causare l'eccezione tramite try. Le eccezioni possono essere provocate
esplicitamente utilizzando raise. Se scatta una eccezione, questa viene
confrontata con le possibili eccezioni che si vogliono gestire, usando la
clausola except. Non ci deve essere necessariamente una sola clausola
except ma anzi è utile che ce ne sia più d'una. Scatterà quella
corrispondente al tipo di eccezione sollevato. Se nessuna va bene,
l'eccezione si propaga come se non ci fosse stato alcun controllo. Questa
procedura è anche il modo più corretto di gestirla: controllare gli errori
che si prevedono e lasciar passare quelli inaspettati in modo che in fase
di test e debug si possano rilevare le condizioni di errore non previste.
Accenniamo infine al fatto che in Python la try può anche avere le
clausole else e finally. La else viene eseguita se il codice sottoposto a
try non causa eccezioni. La clausola finally invece viene eseguita in ogni
caso, sia nel caso che il codice causi eccezioni, sia nel caso che tutti
fili liscio. È anche possibile utilizzare classi definite dall'utente per
organizzare gerarchicamente le eccezioni. Anche questo non lo trattiamo in
dettaglio per motivi di spazio.
Esempio: Gestione Form
Concludiamo l'articolo con un esempio un po' più dettagliato e
significativo: un piccolo programma che può essere usato per i vostri
script Web di gestione form. Tengo a precisare che l'esempio qui
pubblicato è stato scritto utilizzando Windows 98 con Personal Web Server.
L'unico accorgimento per utilizzarlo in questo ambiente è quello di
aggiungere al registro la key
"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters\Script
Map\.py" con valore di tipo stringa "C:\Python\Python.exe %s", e di porre
i vostri script in una directory web-shared con il permesso execute
attivato. Lo script comunque ha girato senza problemi sotto Linux. In
questo caso è stato usato il meccanismo del bang-path, ovvero inserire
come prima riga del codice il riferimento all'interprete dello script con
il prefisso #! Una schermata dello script è visibile in Figura 2, mentre
lo script stesso è nel Listato 2.
Figura 2
Listato 2
#!/usr/bin/python
# Parameters
REREFER="
http://192.168.1.4/python/form.py"
# imports
import cgi
import string
# Print the Form
def print_form(err, nome, cognome,
email):
print """
Modulo
Richiesta di Informazioni
Modulo Richiesta
Informazioni
Si prega di specificare i suoi
dati.
Verrà rincontattato al più
presto.
"""
if err:
print "
Errore
nel modulo: "+err+"
"
# output form with current fields
print """
Nome:
Cognome:
Email:
""" % (REREFER, nome,
cognome, email)
def form_check(form):
err = ""
nome = ""
cognome = ""
email = ""
if not form.has_key("nome"):
err = err + "Specificare
il nome"
else:
nome = form["nome"].value
if not form.has_key("cognome"):
err = err + "Specificare
il cognome"
else:
cognome = form["cognome"].value
if not form.has_key("email"):
err = err + "Specificare
l'email"
else:
email = form["email"].value
if string.find(email, "@")
== -1:
err = err + "Il
formato della email non e' corretto"
return (err, nome, cognome, email)
def send_mail(form):
email = """
Nome.....: %s
Cognome..: %s
Email....: %s
""" %
(form['nome'].value, form['cognome'].value, form['email'].value)
print """
Modulo
Richiesta di Informazioni
Conferma Richiesta
E' stata inviata la seguente richiesta
di informazioni:
%s
""" % (email)
# send mail here...
# Always
print "Content-type:
text/html\n\n"
form = cgi.FieldStorage()
(err, nome,cognome,email) =
form_check(form)
if form.has_key("invia"):
if err:
print_form(err, nome, cognome, email)
else:
send_mail(form)
else:
# first run
print_form("",nome, cognome,
email)
print "La ringraziamo
per la preferenza accordataci.Cordiali Saluti."
Spendiamo due parole sul funzionamento dello script anche perché il Python
è posizionabile come una alternativa al Perl, e gli script CGI sono
probabilmente il campo di applicazione più immediato del Python. Nel
nostro script abbiamo utilizzato il modulo standard cgi per decifrare i
parametri dello script. Come è noto il protocollo CGI invia i dati in un
formato encrittato non particolarmente user-friendly. Chiamando form =
cgi.FieldStorage viene costruito un oggetto contente i parametri passati
allo script decifrati. A questo oggetto è possibile accedere come array
associativo, estraendo i campi della form: form["nome"], eccetera.
Attenzione che se si accede ad un campo non definito si ottiene una
eccezione, per cui occorre verificare l'esistenza di una chiave usando
form.has_key("nome"). Nello script abbiamo anche usato altre due feature
del Python adatte alla generazione di pagine Web: il triple quote """ e
l'operatore di I/O %. Per inserire in uno script Python stringhe di testo
contenenti newline si deve usare come delimitatore tre virgolette. Un
altro aspetto importante è che la print stampa una stringa, e le stringhe
sono in Python immutabili. Per cui, anche se è possibile, fare "taglia e
cuci" con le stringhe per comporre la pagina di output, è abbastanza
inefficiente e scomodo. Per ovviare, esiste un meccanismo di output
analogo alla printf del C, che illustriamo con un esempio:
>>> x = 1
>>> y = 'hello'
>>> z = 64
>>> print "x=%d y=%s z=%c" % (x,y,z)
La stringa che segue il print contiene delle specifiche di formato,
composte dal % seguito da un carattere: d indica i numeri decimali, s le
stringhe e c i caratteri. Le specifiche di formato vengono sostituite dai
parametri che seguono l'operatore % dopo la stringa. Nell'esempio vediamo
come il %d venga sostituito dal valore decimale di x, il %s dalla stringa
y mentre il %c genera il carattere il cui codice ascii è contenuto nella
variabile z (il codice ascii di
'@'
è appunto 64).
Conclusioni
Il Python sta crescendo molto ed occupa ormai un posto rispettabile nel
mondo dei linguaggi di scripting, ormai quasi al pari del più noto Perl.
In effetti, una chiara prova della diffusione del linguaggio è data da
freshmeat.net, un sito che pubblica il nuovo freeware disponibile in rete:
freshmeat riportava 10 nuovi package Perl recenti e ben 8 Python… Come
dire, il linguaggio si avvicina in popolarità e diffusione al Perl e
conquista ogni giorno nuovi cultori. Spero con questi articoli di aver
contribuito alla sua diffusione, con lo scopo non di proporre un poco
utile linguaggio per passare qualche momento di relax, ma uno ottimo
strumento da utilizzare in pratica per risolvere ben precise categorie di
problemi (nella fattispecie scripting Web, System Adminstration e supporto
alla programmazione).
Michele Sciabarrà, laureato in Scienze dell'Informazione, è direttore
tecnico di SATORI Network Solutions, ditta marchigiana focalizzata su Java
e le tecnologie di Internet. Programma in svariati linguaggi da 15 anni, e
in Java da quando il linguaggio era in versione alpha. È stato tra gli
espositori di applicazioni Java già alla 1st Italian Java Conference, ha
scritto decine di articoli su Java e sviluppato numerose applicazioni in
Java. Mantiene sul Web un corso online di Java in italiano
(http://www.satorins.com/CorsoJava)
con cui mi sto
e tutti i
come fa Guido