You are here: Partenza > Dive Into Python > Recensione in 5 minuti | << >> | ||||
Dive Into PythonPython per programmatori esperti |
Benvenuto in Python. Immergiamoci.
Su Windows, avete diverse alternative per installare Python.
Con Mac OS X, ci sono due possibili alternative per installare Python: o lo si installa, oppure no. Probabilmente, voi volete installarlo.
Mac OS 9 non include alcuna versione di Python, ma l'installazione è molto semplice e non ci sono altre alternative.
Per installare su RedHat Linux, avete bisogno di scaricare l'RPM da http://www.python.org/ftp/python/2.3.2/rpms/ ed installarlo con il comando rpm.
Se siete abbastanza fortunati da utilizzare Debian GNU/Linux, potete installare con il comando apt.
Se preferite compilare dai sorgenti, potete scaricare i sorgenti di Python da http://www.python.org/ftp/python/2.3.2/ ed effettuare i soliti configure, make, make install.
Adesso che abbiamo Python, che cos'è questa shell interattiva che abbiamo lanciato?
Dovreste adesso avere una versione di Python installata che lavora per voi.
Ecco un completo e funzionante programma in Python.
Python supporta le funzioni come molti altri linguaggi, ma non necessita di header file separati come il C++ o sezioni di interfaccia/implementazione come il Pascal. Quando avete bisogno di una funzione, basta che la dichiariate e la definiate.
Potete documentare una funzione Python dandole una docstring (stringa di documentazione ndr.).
Una funzione, come ogni altra cosa in Python, è un oggetto.
Le funzioni in Python non hanno un inizio o fine esplicito, nessuna parentesi graffa che indichi dove il codice inizia o finisce. L'unico delimitatore sono i due punti (“:”) e l'indentazione del codice.
I moduli in Python sono oggetti ed hanno diversi attributi utili. Potete usarli per testare i moduli dopo che li avete scritti.
Uno dei tipi predefiniti in Python è il dizionario che definisce una relazione uno-a-uno tra chiavi e valori.
Le liste sono, tra i tipi di dati in Python, la vera forza motrice. Se la vostra sola esperienza con le liste sono gli array in Visual Basic o (Dio ve ne scampi!) il datastore di Powerbuilder, fatevi forza e osservate come si usano in Python.
Una tupla è una lista immutabile. Una tupla non può essere modificata in alcun modo una volta che è stata creata.
Python possiede il concetto di variabili locali e globali come molti altri linguaggi, ma non contempla la dichiarazione esplicita delle variabili. Le variabili cominciano ad esistere quando assegnamo loro un valore e vengono automaticamente distrutte quando non servono più.
Una delle più comode scorciatoie di programmazione in Python consiste nell'usare sequenze per assegnare valori multipli in un colpo solo.
Python supporta la formattazione dei valori nelle stringhe. Sebbene ciò possa comprendere espressioni molto complicate, il modo più semplice per utilizzarle consiste nell'inserire valori in una stringa attraverso l'istruzione %s.
Una delle più potenti caratteristiche di Python sono le list comprehension (descrizioni di lista), che utilizzano una tecnica compatta per mappare una lista in un'altra, applicando una funzione ad ognuno degli elementi della lista.
Avete una lista di coppie chiave-valore nella forma chiave=valore e volete concatenarle in una singola stringa. Per concatenare qualunque lista di stringhe in una singola stringa, usate il metodo join di un oggetto stringa.
Il programma odbchelper.py ed il suo output dovrebbero ora esservi perfettamente chiari.
Capitolo 3. La potenza dell'introspezione
Qui abbiamo un programma Python completo e funzionante. Dovreste essere in grado di capire un bel po' di cose solamente guardando l'esempio. Le linee numerate illustrano concetti trattati nella sezione Conoscere Python. Non preoccupatevi se il resto del codice sembra intimidatorio; imparerete tutto nel corso di questo capitolo.
Python permette agli argomenti delle funzioni di avere un valore predefinito; se la funzione è chiamata senza l'argomento, l'argomento prende il suo valore predefinito. Inoltre gli argomenti possono essere specificati in qualunque ordine usando gli argomenti con nome. Le stored procedure in SQL Server Transact/SQL possono farlo; se siete dei guru nella programmazione via script di SQL Server potete saltare questa parte.
Python ha un piccolo insieme di funzioni built-in estremamente utili. Tutte le altre funzioni sono suddivise in moduli. Si tratta di una decisione coscienziosa, per preservare il nucleo del linguaggio dall'essere soffocato come in moltri altri linguaggi di script (coff coff,Visual Basic).
Già sapete che le funzioni in Python sono oggetti. Quello che non sapete è che potete ottenere un riferimento da una funzione senza conoscere il suo nome fino al momento dell'esecuzione, utilizzando la funzione getattr.
Come già si è detto, Python offre potenti strumenti per mappare delle liste in liste corrispondenti, per mezzo delle “list comprehension”. Queste possono essere combinate con un meccanismo di filtro, facendo in modo che alcuni elementi delle liste vengano mappati ed altri vengano ignorati completamente.
In Python, gli operatori and e or eseguono le operazioni di logica booleane che ci si aspetta dal loro nome, ma non restituiscono valori booleani; essi restituiscono invece il valore di uno degli elementi che si stanno confrontando.
Python supporta un'interessante sintassi che vi permette di definire al volo delle piccole funzioni di una sola riga. Derivate dal Lisp, queste funzioni lambda possono essere usate ovunque sia richiesta una funzione.
L'ultima riga di codice, l'unica che ancora non abbiamo analizzato, è quella che svolge l'intero lavoro. Ma adesso il lavoro è semplice, perché ogni cosa di cui abbiamo bisogno è già impostata come serve a noi. Tutte le tessere sono al loro posto; è ora di buttarle giù.
Il programma apihelper.py ed il suo output ora dovrebbero essere chiari.
Capitolo 4. Una struttura orientata agli oggetti
Eccovi un completo e funzionante programma in Python. Leggete la docstring del modulo, le classi e le funzioni, in modo da avere un'idea di cosa faccia e come lavori questo programma. Come al solito, non curatevi delle parti che non comprendete; il resto del capitolo è fatto per loro.
Python utilizza due modi per importare i moduli. Entrambi sono utili e dovreste sapere quando usarli. Il primo, import module, l'avete già visto nel capitolo 2. Il secondo, raggiunge lo stesso scopo, ma funziona in modo differente.
Python è completamente orientato agli oggetti: potete definire le vostre classi, ereditare dalle vostre classi o da quelle built-in ed istanziare le classi che avete definito.
Istanziare una classe in Python è molto semplice. Per istanziare una classe, basta semplicemente chiamare la classe come se fosse una funzione, passandole gli argomenti che il metodo __init__ definisce. Il valore di ritorno sarà il nuovo oggetto.
Come avete visto, FileInfo è una classe che agisce come un dizionario. Per esplorare ulteriormente questo aspetto, diamo uno sguardo alla classe UserDict nel modulo UserDict, che è l'antenato della nostra classe FileInfo. Non è nulla di speciale; la classe è scritta in Python e memorizzata in un file .py, proprio come il nostro codice. In particolare, è memorizzata nella directory lib della vostra installazione di Python.
In aggiunta ai normali metodi delle classi, c'è un certo numero di metodi speciali che le classi Python possono definire. Invece di essere chiamati direttamente dal vostro codice (come metodi normali), i metodi speciali sono chiamati per voi da Python in particolari circostanze o quando viene adoperata una certa sintassi.
Ci sono molti più metodi speciali dei soli __getitem__ e __setitem__. Alcuni di questi vi permettono di emulare funzionalità che non avreste mai conosciuto.
Conoscete già gli attributi dato, che sono variabili di una specifica istanza di una classe. Python supporta anche gli attributi di classe, che sono variabili riferite alla classe stessa.
Come molti linguaggi, anche Python ha il concetto di funzioni private, che non possono essere chiamate dall'esterno del loro modulo; metodi privati di una classe, che non possono essere chiamati dall'esterno della loro classe ed attributi privati, che non possono essere referenziati dall'esterno della loro classe. Al contrario di molti linguaggi, il fatto che una funzione, metodo o attributo in Python sia pubblico o privato viene determinato interamente dal suo nome.
Come molti linguaggi orientati agli oggetti, Python consente la manipolazione delle eccezioni tramite i blocchi try...except.
Python ha una funzione built-in, open, per aprire un file su disco. open ritorna un oggetto di tipo file, che dispone di metodi e attributi per ottenere informazioni sul file aperto e manipolarlo.
Come molti altri linguaggi, Python ha i cicli for. L'unica ragione per cui non si sono visti finora è perché Python è valido per così tante cose che spesso non se ne sente tanto il bisogno.
I moduli, come qualunque altra cosa in Python, sono oggetti. Una volta importato, si può sempre ottenere un riferimento ad un modulo attraverso il dizionario globale sys.modules.
Il modulo os ha molte funzioni utili per manipolare file e processi e os.path ha molte funzioni per manipolare percorsi di file e directory.
Ancora una volta tutte le nostre pedine del domino sono al loro posto. Abbiamo visto come funziona ogni linea di codice, adesso facciamo un passo indietro e vediamo come il tutto venga messo insieme.
Adesso il programma fileinfo.py dovrebbe avere un senso compiuto.
Spesso in comp.lang.python trovo domande del genere: “Come posso creare una lista di tutti gli [headers | immagini | collegamenti] presenti nel mio documento HTML?” “Come posso [analizzare | tradurre | modificare] il testo del mio documento HTML senza modificare i tag?” “Come posso [aggiungere | rimuovere | mettere tra apici] gli attributi di tutti i tag del mio HTML in una volta sola?” Questo capitolo risponderà a tutte queste domande.
L'elaborazione dell'HTML è suddivisa in tre passi: spezzare l'HTML nei suoi elementi costitutivi, giocherellare con questi pezzi, infine ricostruire i pezzi nuovamente nell'HTML. Il primo passo è fatto da sgmllib.py, che è parte della libreria standard di Python
Per estrarre informazioni da documenti HTML, create una sottoclasse SGMLParser e definite metodi per ogni tag o altro che volete catturare.
SGMLParser non produce nulla da solo. Analizza, analizza e analizza, e chiama un metodo per ogni cosa interessante che trova, ma il metodo non fa nulla. SGMLParser è un consuma HTML: prende il codice HTML e lo divide in piccoli pezzi strutturati. Come avete visto nella sezione precedente, potete creare una sottoclasse di SGMLParser per definire classi che catturano tag specifici e producono cose utili, come la lista dei collegamenti delle pagine web. Adesso facciamo un ulteriore passo avanti, per definire la classe che cattura ogni cosa che SGMLParser rilascia, e quindi ricostruire l'intero documento HTML. In termini tecnici, questa classe sarà un produttore di codice HTML.
Python dispone di due funzioni built-in, locals e globals che forniscono un accesso basato sui dizionari alle variabili locali e globali.
Esiste una forma alternativa per la formattazione di stringhe che usa i dizionari al posto delle tuple di valori.
Una domanda ricorrente su comp.lang.python è: “Io ho un gruppo di documenti HTML con i valori degli attributi espressi senza virgolette e voglio virgolettarli tutti in maniera opportuna. Come posso farlo?” [10] (Questa situazione è generalmente causata da un responsabile di progetto, convertito alla religione “HTML è uno standard”, che si aggiunge ad un grosso progetto e annuncia che tutte le pagine HTML devono essere validate da un verificatore di HTML. Avere i valori degli attributi senza virgolette è una violazione comune dello standard HTML.) Qualunque sia la ragione, è facile rimediare ai valori degli attributi senza virgolette, se si filtra il documento HTML attraverso BaseHTMLProcessor.
La classe Dialectizer è una semplice (e un po' stupida) specializzazione della classe BaseHTMLProcessor. Questa classe sottopone un blocco di testo ad una serie di sostituzioni, ma al contempo fa in modo che tutto ciò che è racchiuso in un blocco <pre>...</pre> rimanga inalterato.
Le espressioni regolari sono un strumento potente (e piuttosto standardizzato) per cercare, sostituire o analizzare del testo contenente complessi schemi di caratteri. Se avete già usato espressioni regolari in altri linguaggi (come il Perl), potete saltare questa sezione e leggere direttamente il sommario del modulo re per avere una panoramica delle funzioni disponibili e dei loro argomenti.
È tempo di mettere a frutto tutto quello che abbiamo imparato finora. Spero che abbiate prestato attenzione.
Python fornisce uno strumento potente, il modulo sgmllib.py, per manipolare codice HTML trasformando la sua struttura in un oggetto modello. È possibile usare questo strumento in molti modi diversi.
Ci sono due principali metodi per lavorare con l'XML. Il primo è chiamato SAX (“Simple API for XML”), funziona leggendo l'XML un pezzo per volta e chiamando un metodo per ogni elemento trovato. Se avete letto il capitolo Elaborare HTML, dovrebbe risultarvi familiare, perché è così che lavora il modulo sgmllib. L'altro è chiamato DOM (“Document Object Model”), funziona leggendo l'intero documento XML in un'unica volta e creando una rappresentazione interna dell'XML basata su classi native Python collegate in una struttura ad albero. Python ha dei moduli standard per entrambi i tipi di parsing, ma questo capitolo affronterà solo l'uso del DOM.
Analizzare un documento XML è estremamente semplice: una sola riga di codice. Comunque, prima di studiare questa riga di codice, dobbiamo fare una piccola deviazione per parlare dei package.
Come stavo dicendo, analizzare un documento XML è molto semplice: una riga di codice. Dove andare poi, dipende da voi.
Unicode è un sistema per rappresentare i caratteri di tutti i differenti linguaggi del mondo. Quando Python analizza un documento XML, tutti i dati sono immagazzinati in memoria sottoforma di unicode.
Attraversare documenti XML passando da un nodo all'altro può essere noioso. Se state cercando qualcosa in particolare, bene in profondità nel vostro documento XML, c'è una scorciatoia che potete usare per trovarlo più velocemente: getElementsByTagName.
Gli elementi XML possono avere uno o più attributi ed è incredibilmente semplice accedervi una volta che avete analizzato il documento XML.
Uno dei punti di forza di Python è il suo binding dinamico, ed uno degli usi più potenti del binding dinamico sono gli oggetti file (ovvero, che si comportano come dei file).
Gli utenti UNIX hanno già familiarità con i concetti di standard input, standard output e standard error. Questa sezione è per il resto di voi.
kgp.py impiega alcuni trucchi che potrebbero esservi utili nella elaborazione XML. Il primo trucco consiste nel trarre vantaggio dalla consistente struttura dei documenti in input per costruire una cache di nodi.
Un'altra utile tecnica quando analiziamo documenti XML consiste nel trovare tutti gli elementi figli diretti di un particolare elemento. Per esempio, nel nostro file grammar, un elemento ref può avere alcuni elementi p, ognuno dei quali può contenere molte cose, inclusi altri elementi p. Vogliamo trovare gli elementi p che sono figli del ref, non gli elementi p che sono figli degli altri elementi p.
Il terzo suggerimento utile per processare gli XML comporta la separazione del vostro codice in funzioni logiche, basate sui tipi di nodi e nomi di elementi. I documenti XML analizzati sono fatti di vari tipi di nodi, di cui ognuno rappresenta un oggetto Python. Il livello base del documento stesso è rappresentato da un oggetto Document. Document contiene uno o più oggetti Element (per i tags XML reali), ognuno dei quali può contenere altri oggetti Element, oggetti Text (per parti di testo), od oggetti Comment (per commenti incorporati). Python rende semplice scrivere uno smistatore per separare la logica per ciascun tipo di nodo.
Python supporta pienamente la creazione di programmi che possono essere eseguiti da riga di comando, completi di argomenti, sia con flag nel formato breve che nel formato esteso per specificare le varie opzioni. Nessuno di questi è specifico di XML, ma questo script fa un buon uso dell'interpretazione da riga di comando, dunque pare un buon momento per menzionarla.
Abbiamo coperto una buona distanza. Facciamo un passo indietro e vediamo come si mettono assieme tutti i pezzi.
Python viene rilasciato con delle potenti librerie per l'analisi e la manipolazione dei documenti XML. minidom prende un file XML e lo analizza in un albero di oggetti Python, permettendo l'accesso casuale ad elementi arbitrari. Inoltre, questo capitolo mostra come Python può essere usato per creare dei “veri” script da riga di comando autonomi, completi di flag da riga di comando, argomenti da riga di comando, gestione degli errori ed anche la possibilità di acquisire come input il risultato di un programma precedente.
Capitolo 7. Test delle unità di codice
Nei capitoli precedenti, ci si è “tuffati” immediatamente nell'analisi del codice, cercando poi di capirlo il più velocemente possibile. Ora che avete immagazzinato un po' di Python, faremo un passo indietro e analizzeremo ciò che si fa prima di scrivere il codice.
Ora che abbiamo completamente definito il comportamento che ci aspettiamo dalle nostre funzioni di conversione, faremo qualcosa di inaspettato: scriveremo un modulo di test che faccia eseguire a queste funzioni il proprio codice e verifichi che esse si comportino come vogliamo. Avete letto bene: andremo a scrivere del codice per verificare altro codice che non abbiamo ancora scritto.
La parte fondamentale della verifica delle unità di codice è costruire i singoli test. Un test risponde ad una singola domanda sul codice che si sta verificando.
Non è abbastanza verificare che la nostra funzione abbia successo quando gli input sono validi; occorre anche verificare che la funzione vada in errore quando riceve input non validi. E non basta che vada in errore: deve farlo nel modo che ci si aspetta.
Spesso vi capiterà di scoprire che un'unità di codice contiene un insieme di funzioni reciproche, di solito in forma di funzioni di conversione, laddove una converte A in B e l'altra converte B in A. In questi casi, è utile creare un “test di consistenza” per essere sicuri che si possa converire A in B e poi riconvertire B in A senza perdere precisione, incorrere in errori di arrotondamento o in qualche altro malfunzionamento.
Ora che i nostri test delle unità di codice sono pronti, è tempo di cominciare a scrivere il codice che stiamo cercando di verificare con i nostri test. Faremo questo in più fasi, in modo che si possa osservare dapprima come tutti i test falliscano, e poi come a poco a poco abbiano successo man mano che riempiamo gli spazi vuoti all'interno del modulo roman.py.
Ora che abbiamo delineato l'infrastruttura del modulo roman, è tempo di cominciare a scrivere il codice e passare con successo qualche test.
Adesso che la funzione toRoman si comporta correttamente con input validi (numeri da 1 a 3999), è tempo di fare in modo che lo faccia anche con input non validi (qualsiasi altra cosa).
Ora che la funzione toRoman è completa, è tempo di cominciare a scrivere il codice di fromRoman. Grazie alla nostra struttura dati dettagliata che mappa i singoli numeri romani elementari negli interi corrispondenti, la cosa non è più difficile dell'aver scritto la funzione toRoman.
Ora che fromRoman funziona correttamente con input validi, è tempo di far combaciare l'ultimo pezzo del puzzle: farla funzionare con input non validi. Senza troppi giri di parole cerchiamo di osservare una stringa e di determinare se è un numero romano valido. Questo è ancor più difficoltoso se paragonato agli input validi in toRoman, ma noi abbiamo a disposizione un potente strumento a disposizione: le espressioni regolari
A dispetto dei nostri migliori sforzi per scrivere test completi per le unità di codice, capita di fare degli errori di programmazione, in gergo chiamati bachi (“bug”). Un baco corrisponde ad un test che non è stato ancora scritto.
A dispetto dei vostri migliori sforzi di bloccare i vostri clienti in un angolo per tirargli fuori gli esatti requisiti del software da sviluppare, sotto la minaccia di sottoporli ad orribili operazioni con forbici e cera bollente, i requisiti cambieranno lo stesso. Molti clienti non sanno cosa vogliono fino a quando non lo vedono, ed anche allora, non sono così bravi a dettagliare esattamente il progetto, a tal punto da fornire indicazioni che possano risultare utili. Ed anche nel caso lo siano, chiederanno sicuramente di più per la prossima versione del software. Siate quindi preparati ad aggiornare i vostri test quando i requisiti cambieranno.
La cosa migliore nel fare test esaustivi delle unità di codice non è la sensazione piacevole che si ha quando tutti i test hanno finalmente successo, e neanche la soddisfazione di quando qualcun altro ti rimprovera di aver scombinato il loro codice e tu puoi effettivamente provare che non è vero. La cosa migliore nell'effettuare i test delle unità di codice è la sensazione che ti lascia la libertà di rifattorizzare senza provare rimorsi.
Un lettore intelligente dopo aver letto la sezione precedente ha subito fatto il passo successivo. Il più grosso grattacapo (e peggioratore delle prestazioni) nel programma com'è scritto al momento è l'espressione regolare, che è necessaria perché non abbiamo altro modo di decomporre un numero romano. Ma ci sono solo 5000 numeri romani: perché non ci costruiamo all'inizio una tavola di riferimento e non usiamo quella? Questa idea è ancora migliore una volta capito che è possibile rimuovere del tutto l'uso delle espressioni regolari. Una volta costruita la tavola di riferimento per convertire interi in numeri romani, è possibile costruire la tavola inversa per convertire i numeri romani in interi.
Il test delle unità di codice è un concetto forte che, se opportunamente implementato, può ridurre sia i costi di manutenzione che aumentare la flessibilità in ogni progetto a lungo termine. È però anche importante capire che i test delle unità di codice non sono una panacea, una bacchetta magica che risolve tutti i problemi, o una pallottola d'argento. Scrivere dei buoni test è difficile, e mantenerli aggiornati richiede disciplina (specialmente quando i clienti vi stanno chiedendo a gran voce la soluzione di qualche problema critico nel software). I test delle unità di codice non sono un sostituto per le altre forme di verifica del codice, tra cui i test funzionali, i test di integrazione e i test di accettazione. Rappresentano tuttavia una pratica realizzabile, e funzionano, ed una volta che li avrete provati vi chiederete come avete fatto ad andare avanti senza di loro.
Capitolo 8. Programmazione orientata ai dati
Nel capitolo relativo al Test delle unità di codice, ne abbiamo discusso la filosofia e ne abbiamo vista l'implementazione in Python. Questo capitolo si dedicherà a tecniche specifiche di Python, più avanzate, basate sul modulo unittest. Se non avete letto il capitolo Test delle unità di codice, vi perderete a metà lettura. Siete stati avvertiti.
Quando lanciate gli script Python da linea di comando, qualche volta torna utile sapere dov'è localizzato lo script corrente sul disco fisso.
Avete già familiarità con l'utilizzo delle list comprehensions per filtrare le liste. C'è un'altro modo per raggiungere lo stesso risultato, che alcune persone considerano più espressivo.
Siete già abituati ad usare la list comprehensions per mappare una lista in un altra. C'è un altro modo per fare la stessa cosa, usando la funzione built-in map. Funziona in modo molto simile alla funzione filter.
Per adesso probabilmente vi starete grattando la testa chiedendovi perché questo modo di fare sia migliore rispetto all'usare un ciclo for e chiamate dirette a funzioni. Ed è una domanda perfettamente legittima. È principalmente una questione di prospettiva. Usare map e filter vi obbliga a focalizzare l'attenzione sui dati.
Ok, abbiamo filosofeggiato abbastanza. Vediamo come si importano dinamicamente i moduli.
Ora abbiamo imparato abbastanza da poter scomporre le prime sette linee dell'esempio di questo capitolo: leggere una directory ed importare alcuni dei moduli che vi sono contenuti.
Spiacente, questa parte del capitolo ancora non è stata scritta. Provate a controllare https://book.diveintopython.org/ per gli aggiornamenti.
<< Ulteriori letture |
| | |
Consigli e trucchi >> |