Guida Python 3 Ita
Guida Python 3 Ita
La Traduzione:
INDICE
9.9. Iteratori
9.10. Generatori
9.11. Generatore di Espressioni
10. Panoramica Sulle Librerie Standard
10.1. Interfaccia al Sistema Operativo
10.2. File Jolly
10.3. Argomenti della Linea di Comando
10.4. Reidirizzamento Output degli Errori e Terminazione Programma
10.5. Corrispondenza di Stringhe
10.6. Matematica
10.7. Accesso a Internet
10.8. Date e Tempo
10.9. Compressione Dati
10.10. Misurazione delle Prestazioni
10.11. Controllo Qualit
10.12. Tutto compreso
11. Panoramica Sulle Librerie Standard Parte II
11.1. Output Formatting
11.2. Modellazione
11.3. Lavorare con i Data Record Layouts Binari
11.4. Multi-threading
11.5. Logging
11.6. Referimenti deboli
11.7. Strumenti per Lavorare con le Liste
11.8. Decimal Floating Point Arithmetic
12. E Adesso?
13. Input ed Editing Interattivo Sostituzioni e Cronologia
13.1. Editare le Linee
13.2. Sostituzione cronologica
13.3. Tasti Collegati
13.4. Alternative all'Interprete Interattivo Predefinito
14. Aritmetica in Virgola Mobile: Problemi e Limiti
14.1. Errori di Rappresentazione
Python un linguaggio interpretato, ci significa che possibile risparmiare molto tempo durante lo
sviluppo del programma, perch non necessaria la continua compilazione e conseguente linkaggio.
L'interprete pu essere utilizzato interattivamente il che lo rende facile per sperimentare le caratteristiche
proprie, scrivere programmi usa e getta per testare funzioni durante lo sviluppo di un programma
principale. Inoltre anche un'utile calcolatrice.
Python consente ai programmi di essere scritti in modo compatto e di essere di facile lettura in quanto
obbliga a scriverli in un certo modo. I programmi scritti in Python sono in genere molto pi brevi dei
programmi equivalenti C C + + o Java, per diverse ragioni fra cui:
I tipi di dati di alto livello consentono di esprimere operazioni complesse anche con una singola
istruzione;
Le istruzioni vengono raggruppate tramite indentazione anzich usare parentesi iniziale e finale o
blocchi tipo INIZIO BLOCCO FINE BLOCCO;
Non necessario dichiarare alcuna variabile.
Nota:
Quest'ultima caratteristica, far storcere il naso ad alcuni programmatori specialmente di provenienza C
C++ e Java. Ma come vedremo pi avanti, la richiesta di scrittura di codice talmente minore rispetto ad
altri linguaggi per esempio da minimizzare la questione. Inoltre essendo fortemente dinamico, usa un'
approccio totalmente diverso da altri linguaggi (argomento complesso che sar trattato pi avanti)
Python estendibile: se sapete programmare in C facile aggiungere una nuova funzione o un modulo pre
costruito per l'interprete, sia per eseguire operazioni critiche alla massima velocit, o per collegare
programmi Python a librerie che possono essere disponibili solo in forma binaria (ad esempio librerie
grafiche proprietarie o di sistema). Una volta che siete diventati davvero pratici, possibile collegare
l'interprete Python in un'applicazione scritta in C e usarlo come linguaggio di estensione o di comando
per tale applicazione.
Molti si domanderanno perch si chiami Python! Non ha nulla a che vedere con i serpenti, il suo autore
Guido Van Rossum un'appassionato della serie televisiva di sketch Monty Python". Fare riferimenti
alle comiche dei Monty Python nella documentazione permesso, non solo ma incoraggiato! (l'uso
della parola spam ad esempio veramente ossessiva (sar perch la carne in scatola non mi fa impazzire,
ma tant'...)
Ora che sarete senz'altro entusiasti di Python, vi consigliamo di esaminare in maggior dettaglio il
linguaggio e il suo ambiente. Dal momento che il modo migliore per imparare una linguaggio quello di
usarlo, questa guida vi invita a giocare con l'interprete Python ed ad eseguirne gli esempi.
Nel prossimo capitolo, verranno spiegati i meccanismi per utilizzare l'interprete. Si tratta di informazioni
piuttosto banali, ma essenziali per provare gli esempi mostrati successivamente. Il resto della guida,
introduce varie caratteristiche di Python attraverso esempi iniziando con semplici espressioni, istruzioni e
tipi di dati, attraverso funzioni e moduli, ed infine, toccando concetti avanzati come le eccezioni e le classi
definite dall'utente ecc.
Python
su
una
macchina
Unix/Linux,
generalmente
installato
in
al cui interno racchiuso il comando nella sua interezza. Alcuni moduli Python sono utili anche come
script. Questi possono essere richiamati utilizzando python -m module [arg] ..., che esegue il
file di origine per il modulo, come se si fosse scritto il suo nome completo sulla riga di comando. Quando
si utilizza un file di script, a volte utile essere in grado di eseguire lo script ed entrare in modalit
interattiva successivamente. Questo pu essere fatto passando -I prima dello script.
modalit interattiva ritorna al prompt primario. Quando invece l'input venuto da un file, esso esce con
uno stato diverso da zero dopo aver stampato la traccia dello stack. (Eccezioni gestite da una clausola
except in un'istruzione try
non sono errori in questo contesto.) Alcuni errori sono
incondizionatamente fatali e provocano un'uscita forzata con un valore diverso da zero, questo vale per le
incoerenze interne e alcuni casi tipo esaurimento della memoria disco ecc. Tutti i messaggi di errore
vengono scritti nel flusso di errore standard-output tipicamente il monitor o dove specificato. Digitando il
carattere di interruzione (di solito Ctrl-C o CANC) al prompt primario o secondario si cancella l'input e
ritorna al prompt primario (>>>).
[2] Provocare un'interruzione forzata mentre un comando in esecuzione solleva l'eccezione
KeyboardInterrupt, che pu essere gestita tramite un'istruzione try.
origine:
#*coding:encoding*
Con questa dichiarazione, tutto nel file sorgente verr considerata come avente la codifica encoding
invece di UTF-8. L'elenco dei possibili codifiche pu essere trovata nella Python Library Reference, nella
sezione codecs. Ad esempio, se il vostro editor preferito non supporta file codificati UTF-8 e insiste
sull'utilizzo di qualche altra codifica, possibile per esempio scrivere Windows-1252, per ottenere il
risultato:
#*coding:cp1252*
Ci utilizzer tutti i caratteri di caratteri nei file sorgente in Windows-1252. Il commento speciale
codifica deve essere nella prima riga se da solo o nella seconda linea se presente quella di path
all'interno del file.
Queste impostazioni possono essere utili ma non necessario che le approfondiate adesso.
3.1.1. Numeri.
L'interprete si comporta come una semplice calcolatrice: si pu digitare un'espressione ed esso fornir il
risultato. La sintassi delle espressioni semplice: gli operatori +, -, * e / funzionano come nella maggior
parte degli altri linguaggi (ad esempio, Pascal o C); parentesi anche nidificate (()) possono essere
utilizzati per il raggruppamento e la risoluzione. Per esempio:
>>>2+2
4
>>>505*6
20
>>>(505*6)/4
5.0
>>>8/5#ladivisionerestituiscesempreunnumeroinvirgola
mobile(diversamentedaPython2.x)
1.6
I numeri interi (es. 2, 4, 20) sono di tipo int, quelli con una parte frazionaria (es. 5.0, 1.6) sono di
tipo float. Vedremo di pi su tipi numerici pi avanti nella guida.
Divisione (/) restituisce sempre un float. Per ottenere un risultato intero (scartando qualsiasi risultato
frazionario) possibile utilizzare l'operatore // vedere floor division, per calcolare il resto possibile
utilizzare %:
>>>17/3#classicadivisionerestituisceunnumeroinvirgola
mobile
5.666666666666667
>>>
>>>17//3#divisionechescartalapartedecimale
5
>>>17%3#l'operatore%invecerestituiscelarimanenzadella
divisione
2
>>>5*3+2
17
Con Python possibile usare l'operatore ** per calcolare la potenza di un numero [1]:
>>>5**2#5ilquadrato
25
>>>2**7#2elevatoallapotenzadi7
128
Il segno di uguale (=) viene utilizzato per assegnare un valore a una variabile e non come operatore di
confronto (==). Successivamente, nessun risultato viene visualizzato prima del successivo prompt
interattivo:
>>>altezza=20
>>>larghezza=5*9
>>>altezza*larghezza
900
Se si cercher di utilizzare una variabile a cui non si sia precedentemente assegnato un valore, si generer
un'errore.
>>>n#variabilesenzaassegnazione
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
NameError:name'n'isnotdefined
Python ha un potente supporto per i dati in virgola mobile e operatori di tipo con operandi misti,
convertono l' operando intero a virgola mobile:
>>>3*3.75/1.5
7.5
>>>7.0/2
3.5
In modo interattivo, l'ultima espressione stampata viene assegnata alla variabile _. Ci significa che
quando si utilizza Python come una calcolatrice da tavolo, un po 'pi facile continuare calcoli, ad
esempio:
>>>tassa=12.5/100
>>>prezzo=100.50
>>>prezzo*tassa
12.5625
>>>prezzo+_
113.0625
>>>round(_,2)
113.06
Questa variabile deve essere considerata come a sola lettura da parte dell'utente. Non assegnare
esplicitamente un valore ad essa per utilizzare il suo contenuto, bisogna creare una variabile locale
indipendente per mascherare la variabile precostituita con il suo comportamento magico.
Oltre a int e float, Python supporta altri tipi di numeri, come Decimal e Fraction. Python ha
anche il supporto integrato per i numeri complessi complex numbers, e utilizza il suffisso j o J per
indicare la parte immaginaria (es. 3+5j).
3.1.2. Le Stringhe.
Oltre ai numeri, Python pu anche manipolare stringhe, che possono essere espresse in vari modi. Esse
possono essere racchiuse tra singoli apici ('...') o doppi apici ("...") con lo stesso risultato [2]. il
carattere '\' Pu essere usato per rappresentare le virgolette all'interno di una stringa:
>>>'spamuova'#virgolettesingole
'spamuova'
>>>'all\'ariaaperta'#\permetterelastampadell'apice.
"all'ariaaperta"
>>>"all'ariaaperta"#...oppureutilizzandolevirgolettedoppie
"all'ariaaperta"
>>>'"Si,"hadettosi.'
'"Si,"hadettosi.'
>>>"\"Si,\"hadettosi."
'"Si,"hadettosi.'
Nel interprete interattivo, la stringa di output racchiusa tra virgolette e caratteri speciali sono stampati
usando la barra rovesciata o backslashes. Anche se questo potrebbe talvolta portare un' aspetto diverso per
l' input (le virgolette che racchiudono potrebbero cambiare), le due stringhe sono equivalenti. La stringa
racchiusa tra virgolette doppie se la stringa contiene una singola senza virgolette, altrimenti viene
racchiuso tra virgolette singole. La funzione print() produce un output pi leggibile, omettendo le
virgolette che racchiudono la stringa evitando i caratteri speciali:
>>>print('"Si,"hadettosi.')
"Si,"hadettosi.
>>>s='lineauno.\nlineadue.'#\nsignificanuovalinea
>>>s#senzaprint(),\nvienestampata
'lineauno.\nlineadue.'
>>>print(s)#quiproduceunanuovalinea
lineauno.
lineadue.
Se non si desidera che i caratteri preceduti da \ siano interpretati come caratteri speciali, possibile
utilizzare il raw strings aggiungendo una r prima delle virgolette con questo sistema, l'interprete non
valuter nessuna elaborazione ma semplicemente presenta il tutto cos com':
>>>print('C:\some\nome')#qui\nsignificaunanuovalinea!
C:\some
ome
>>>print(r'C:\some\nome')#notarelarprimadellavirgoletta
C:\some\nome
I letterali stringa possono estendersi su pi righe. Un modo per farlo, usare le triple
virgolette:"""...""" . I fine linea vengono inclusi automaticamente nella stringa, ma possibile
impedire questo comportamento aggiungendo un \ alla fine della prima riga. In questo esempio, viene
prodotto il seguente output :
print("""\
Usare:Queste[OPZIONI]
Visualizzaquesterighe
h...
Hhostname...
""")
Le stringhe possono essere concatenate (incollate assieme sequenzialmente) con l'operatore +, e ripetuto
con *:
>>>#3volte'Pippo',seguitoda'si!'
>>>3*'Pippo'+'si!'
'PippoPippoPipposi!'
Due o pi stringhe letterali (cio quelle racchiuse tra virgolette) l'una accanto all'altra vengono
automaticamente concatenate.
>>>'Py''thon'
'Python'
Questo funziona solo con i letterali ma non con le variabili o espressioni:
>>>prefix='Py'
>>>prefix'thon'#nonpossibileconcatenareunavariabileconuna
stringa.
...
SyntaxError:invalidsyntax
>>>('un'*3)'ium'
...
SyntaxError:invalidsyntax
Se lo scopo quello di concatenare due variabili, allora dovete usare il segno +:
>>>prefix='thon'
'Python'
Questa caratteristica e spesso usata quando si cerca di spezzare stringhe troppo lunghe:
>>>text=('Metterepistringheall'internodi'
'parentesiperunirle.')
>>>text
'Metterepistringheall'internodiparentesiperunirle.'
Le stringhe possono essere indicizzate per cui il primo carattere ha come indice lo 0. Non vi alcuna
distinzione fra caratteri! Semplicemente ognuno rappresenta se stesso:
>>>word='Python'
>>>word[0]#carattereallaposizione0
'P'
>>>word[5]#carattereallaposizione5
'n'
Gli indici possono essere anche numeri negativi, in questo caso il conteggio inizia da destra:
>>>word[1]#l'ultimocarattere
'n'
>>>word[2]#penultimocarattere
'o'
>>>word[6]#ilprimocarattere
'P'
Si noti che poich -0 lo stesso di 0, gli indici negativi partono da -1.
Oltre all'indicizzazione, supportato anche la divisione o slicing (letteralmente 'affettamento'). Mentre
l'indicizzazione viene utilizzata per ottenere singoli caratteri, la divisione viene utilizzata per ottenere
delle sotto stringhe:
>>>word[0:2]#caratteridallaposizione0alla2incluse
'Py'
>>>word[2:5]#caratteridallaposizione0inclusaa5esclusa
'tho'
Si noti come l'inizio sempre incluso, e la fine sempre esclusa. Questo fa in modo che s [: i] + s [i:]
sempre uguale a s:
>>>word[:2]+word[2:]
'Python'
>>>word[:4]+word[4:]
'Python'
Gli indici delle sotto stringhe, hanno valori predefiniti utili; se omesso il primo indice uguale a zero,
cos se omesso il secondo, viene definito dalla lunghezza della sotto stringa.
>>>word[:2]#caratteredall'inizioallaposizione2
'Py'
>>>word[4:]#caratteredallaposizione4allafine
'on'
>>>word[2:]#caratteredallapenultimaposizioneallafine
'on'
Indici fuori intervallo, sono trattati ignorandoli evitando cos errori inutili:
>>>word[4:42]
'on'
>>>word[42:]
''
Le stringhe in Python non possono essere modificate, sono di tipo immutable cio immutabili. Pertanto,
l'assegnamento ad un indice di una stringa costituisce un errore:
>>>word[0]='J'
...
TypeError:'str'objectdoesnotsupportitemassignment
>>>word[2:]='py'
...
TypeError:'str'objectdoesnotsupportitemassignment
Se la modifica di una stringa, si rende necessaria, dovete crearne una nuova:
>>>'J'+word[1:]
'Jython'
>>>word[:2]+'py'
'Pypy'
La funzione precostituita len() restituisce la lunghezza della stringa passatagli:
>>>s='supercalifragilistiespiralitoso'
>>>len(s)
31
Vedere anche:
Text Sequence Type str
Esempi di sequenza di tipi sulle stringhe, supportano le comuni operazioni supportate da tali tipi.
String Methods
Stringhe supportano un gran numero di metodi per le trasformazioni di base e la ricerca.
String Formatting
Informazioni sulla formattazione delle stringhe con str.format() .
printf-style String Formatting
Le vecchie operazioni di formattazione invocate con le stringhe Unicode utilizzano l'operando % alla sua
sinistra. Sono qui descritte in maggiore dettaglio.
3.1.3. Le Liste.
Python possiede un certo numero di tipi di dati composti molto potenti, usati per raggruppare altri valori
fra cui Il pi versatile la lista, che pu essere scritta come un elenco di valori separati da virgole
(articoli) tra parentesi quadre. Le liste possono contenere elementi di tipo diverso, ma di solito gli
elementi sono tutti lo stesso tipo.
>>>quadrati=[1,2,4,9,16,25]
>>>quadrati
[1,2,4,9,16,25]
Come per le stringhe (e tutti gli altri tipi di sequenze precostituite), le liste possono essere indicizzate e
suddivise:
>>>quadrati[0]#restituisceilprimoelemento
1
>>>quadrati[1]
25
>>>quadrati[3:]#suddivideglielementiinunanuovalista
[9,16,25]
Tutte le operazioni di suddivisione, restituiscono un nuovo elenco contenente gli elementi richiesti. Ci
significa che la seguente suddivisione restituisce una nuova (superficiale) copia della lista:
>>>quadrati[:]
[1,2,4,9,16,25]
Le liste supportano anche le operazioni di concatenamento:
>>>quadrati+[36,49,64,81,100]
[1,2,4,9,16,25,36,49,64,81,100]
Diversamente dalle stringhe, che sono immutabili, liste sono un tipo mutabile, cio possibile modificare
il loro contenuto:
>>>cubi=[1,8,27,65,125]#quic'qualcosachenonva
>>>4**3#ilcubodi464,non65!
64
>>>cubi[3]=64#sostituisceilvaloreerrato
>>>cubi
[1,8,27,64,125]
inoltre possibile aggiungere nuovi elementi alla fine della lista, utilizzando il metodo append()
(vedremo di pi sui metodi in seguito):
>>>cubi.append(216)#aggiungeilcubodi6
>>>cubi.append(7**3)#eilcubodi7
>>>cubi
[1,8,27,64,125,216,343]
>>>lettere=['a','b','c','d','e','f','g']
>>>lettere
['a','b','c','d','e','f','g']
>>>#sostituiscealcunivalori
>>>lettere[2:5]=['C','D','E']
>>>lettere
['a','b','C','D','E','f','g']
>>>#oranerimuovealcuni
>>>lettere[2:5]=[]
>>>lettere
['a','b','f','g']
>>>#cancellalalistasostituendolaconunavuota
>>>lettere[:]=[]
>>>lettere
[]
La funzione precostituita len() applicata anche alle liste:
>>>lettere=['a','b','c','d']
>>>len(lettere)
4
E' inoltre possibile nidificarle creare cio delle liste al cui interno sono presenti altre liste e non solo per
esempio:
>>>a=['a','b','c']
>>>n=[1,2,3]
>>>x=[a,n]
>>>x
[['a','b','c'],[1,2,3]]
>>>x[0]
['a','b','c']
>>>x[0][1]
'b'
>>>#seriediFibonacci:
...#lasommadidueelementi,definiscel'elementosuccessivo
...a,b=0,1
>>>whileb<10:
...print(b)
...a,b=b,a+b
...
1
1
2
3
5
8
Quest'esempio, introduce nuove ed importanti caratteristiche.
Il ciclo while viene eseguito fino a quando la condizione (qui: b < 10) rimane vera. In Python,
come in C, qualsiasi valore intero non-zero vero, nulla falso. La condizione pu anche essere
un valore stringa o una lista, di fatto qualsiasi sequenza, qualsiasi cosa con una lunghezza diversa
da zero vero, le sequenze vuote sono false. Il test utilizzato nell'esempio un semplice confronto.
Gli operatori standard di confronto sono scritti come in C: < (minore di), > (maggiore di), ==
(uguale a), <= (minore o uguale a), >= (maggiore o uguale a) e != (non uguale a).
Il corpo del ciclo indentato: l'identazione il modo con cui Python raggruppa le istruzioni. A
differenza di altri linguaggi, Python non utilizza parentesi graffe {} come in C o marcatori di
blocco come in Pascal. Ma usa gli spazi. Al prompt interattivo, necessario digitare una
tabulazione o uno spazio per ogni linea identata cio costituita da 2 so pi spazi. In pratica se non
si possiede un editor di testo con autoidentazione, la possibilit di errori aumenta in quanto il
solo modo con cui Python riconosce le diverse righe di codice. La cosa positiva che non richiede
caratteri terminatori come negli altri linguaggi tipo la virgola il punto e virgola, il ritorno del
carrello ecc. Inoltre costringe il programmatore ad uniformarsi a quello stile piacente o non
piacente a beneficio di chiunque legga il programma. Quando viene immessa in modo interattivo
un'istruzione composta, deve essere seguita da una riga vuota per indicare il suo completamento
(dato che il parser (l'analizzatore di linee di programma) non pu sapere quando si digitato
l'ultima riga). Si noti che ogni riga all'interno di un blocco di base deve essere rientrata nello
stesso modo.
La funzione print() scrive il valore dell'argomento/i dati. Si differenzia dal semplice scrivere
l'espressione che volete (come abbiamo fatto in precedenza negli esempi calcolatrice) nel modo in
cui gestisce pi argomenti, numeri e stringhe. Le stringhe vengono stampate senza virgolette, e
viene inserito uno spazio tra gli elementi, in modo da presentare gli elementi in modo ordinato,
come questo esempio:
>>>i=256*256
>>>print('Ilvaloredii',i)
Ilvaloredii65536
La parola chiave end pu essere usata per evitare la nuova riga dopo l'output, o terminare l'output
con una stringa differente:
>>>a,b=0,1
>>>whileb<1000:
...print(b,end=',')
...a,b=b,a+b
...
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
Note:
[1] Poich ** ha precedenza maggiore rispetto a -3**2 saranno interpretati come (3**2) e quindi
produrre il risultato di -9. Per evitare questo ed ottenere 9, possibile usare (-3)**2.
[2] A differenza di altri linguaggi, caratteri speciali come \n hanno lo stesso significato sia con singoli
('...') e doppi ("...") apici. L'unica differenza tra i due che tra singoli apici non c' bisogno di
usare il carattere di escape \ e viceversa.
Il dato finale non mai parte della sequenza generata; range(10) genera 10 valori, gli indici leciti per
gli elementi di una sequenza di lunghezza 10. E' possibile partire da un altro numero, o specificare un
incremento diverso (persino negativo, a volte questo chiamato il ' passo '):
range(5,10)
5verso9
range(0,10,3)
0,3,6,9
range(10,100,30)
10,40,70
Per scorrere gli indici di una sequenza, possibile combinare range() e len() come segue:
>>>a=['Maria','ha','un','piccolo','agnello']
>>>foriinrange(len(a)):
...print(i,a[i])
...
0Maria
1ha
2un
3piccolo
4agnello
Nella maggior parte dei casi, tuttavia, conveniente utilizzare la funzione enumerate(), vedere
Tecniche dei cicli Looping Techniques.
Una cosa strana succede solo se si stampa un intervallo:
>>>print(range(10))
range(0,10)
In molti casi l'oggetto restituito da range() si comporta come se fosse una lista, ma in realt non lo . E'
un oggetto che restituisce gli elementi successivi nella sequenza desiderata quando si scorre su di esso, ma
in realt non fa realmente una lista, risparmiando cos spazio in quanto non conservato in memoria.
Diciamo un tale oggetto iterabile, cio, adatto come obiettivo per le funzioni e costrutti che si aspettano
qualcosa in cui si possono ottenere elementi successivi fino ad esaurimento dei dati. Abbiamo visto che
l'istruzione for un iteratore. La funzione list() ne un' altro, crea liste di iterabili:
>>>list(range(5))
[0,1,2,3,4]
Pi avanti vedremo altre funzioni che restituiscono iterabili e prendono iterabili come argomento.
Trovatounnumero9
La parola chiave def introduce una definizione di funzione. Essa deve essere seguita dal nome della
funzione e l'elenco tra parentesi dei parametri formali che se sono in numero maggiore di uno, devono
essere separati da virgole.. Le dichiarazioni che formano il corpo della funzione iniziano alla riga
successiva, e devono essere identate.
La prima istruzione del corpo della funzione pu opzionalmente essere una stringa letterale, questa stringa
la stringa di documentazione della funzione o docstring. (Ulteriori informazioni su docstring si trovano
nella documentazione Documentation Strings). Python possiede degli strumenti per la creazione di
documentazione che usano le docstring per produrre automaticamente documentazione in linea o
stampata, o per permettere all'utente una navigazione interattiva attraverso il codice: buona pratica
includere docstring nel codice che si scrive, in modo da prendere l'abitudine ad usarla.
L'esecuzione di una funzione introduce ad una nuova classificazione delle variabili in questo caso locali
alla funzione. Pi precisamente, tutte le assegnazioni di variabili della funzione, vengono memorizzate in
una tabella locale propria della funzione dei simboli locali; quando ci si riferisce ad una variabile, Python
prima guarda dentro questa tabella, poi nelle tabelle dei simboli locali di funzioni che la racchiudono a
sua volte (se esiste), poi nella tabella dei simboli globale, e infine nella tabella di nomi precostituiti.
Pertanto, le variabili globali non possono essere assegnate direttamente ad un valore all'interno di una
funzione (a meno che non denominato in una dichiarazione globale), anche se possono essere referenziate.
I parametri (argomenti) di una chiamata a una funzione vengono introdotti nella tabella dei simboli locale
della funzione chiamata quando essa viene invocata, quindi, gli argomenti sono passati usando una
chiamata per valore (dove il valore sempre un riferimento a un oggetto, non il valore dell'oggetto). [1]
Quando una funzione chiama un'altra funzione, viene creata una nuova tabella locale dei simboli per tale
chiamata e via via cos.
Una definizione di funzione introduce il nome della funzione nella tabella dei simboli corrente. Il valore
del nome della funzione ha un tipo riconosciuto dall'interprete come funzione definita dall'utente. Questo
valore pu essere assegnato ad un altro nome che pu quindi essere utilizzato come funzione. Questo
serve come un meccanismo generale di ridenominazione:
>>>fib
<functionfibat10042ed0>
>>>f=fib
>>>f(100)
01123581321345589
Provenendo da altri linguaggi,, si potrebbe obiettare che fib non una funzione, ma una procedura in
quanto non restituisce un valore. Va ricordato che Python sinteticamente semplifica la stesura del codice
eliminando molti degli orpelli che altri linguaggi hanno! In realt, anche le funzioni senza istruzione
return restituiscono un valore. Questo valore chiamato None ( un nome predefinito). La scrittura
del valore None di norma soppressa dall'interprete se fosse l'unico valore scritto. Lo si pu vedere se
davvero si vuole usando print():
>>>fib(0)
>>>print(fib(0))
None
E 'semplice scrivere una funzione che restituisce un elenco dei numeri della serie di Fibonacci, invece di
stamparli:
>>>deffib2(n):#scriveunasequenzaFibonaccifinoan
..."""stampaunalistacontenentelaserieFibonaccifinoan"""
...risultato=[]
...a,b=0,1
...whilea<n:
...risultato.append(a)#vedisotto
...a,b=b,a+b
...returnrisultato
...
>>>f100=fib2(100)#lachiama
>>>f100#scriveilrisultato
[0,1,1,2,3,5,8,13,21,34,55,89]
Questo esempio, come al solito, mette in luce alcune nuove funzionalit di Python:
L'istruzione return restituisce un valore da una funzione. return senza argomenti espressione,
restituisce None. Anche il fallimento di una funzione restituisce None.
tentativi=tentativi1
iftentativi<0:
raiseIOError('refusenikuser')
print(conferma)
Questa funzione pu essere richiamata in diversi modi:
dando solo l'argomento obbligatorio: quesito('Vuoi davvero uscire?')
dando uno degli argomenti opzionali: quesito('? OK per sovrascrivere il file', 2)
o anche dando tutti gli argomenti: quesito('? OK per sovrascrivere il file', 2, 'Ok, solo s o no')
Questo esempio introduce anche la parola chiave in. Questa verifica se una sequenza contiene un certo
valore.
I valori predefiniti vengono valutati al momento della definizione nella funzione nell'ambito definito, in
modo che:
i=5
deff(arg=i):
print(arg)
i=6
f()
Stamper5.
Avvertenza importante: Il valore predefinito, viene valutato solo una volta. Questo fa differenza quando
il valore predefinito un oggetto mutabile come una lista, un dizionario o istanze nella maggior parte
delle classi. Ad esempio, la seguente funzione accumula gli argomenti ad essa passati in chiamate
successive:
deff(a,L=[]):
L.append(a)
returnL
print(f(1))
print(f(2))
print(f(3))
Verrstampatoquesto:
[1]
[1,2]
[1,2,3]
Se non si desidera che il valore predefinito sia condiviso tra chiamate successive, possibile scrivere la
funzione in questo modo:
deff(a,L=None):
ifLisNone:
L=[]
L.append(a)
returnL
#argomentorichiestoomesso
#argomentosenzachiave
#valoreargomentoduplicato
#argomentochiaveinesistente
In una chiamata alle funzioni, gli argomenti chiave devono seguire argomenti posizionali. Tutti gli
argomenti chiave passati, devono corrispondere ad uno degli argomenti accettati dalla funzione e il loro
ordine non importante ad esempio, colore non un argomento valido per la funzione motore.
Questo include anche argomenti non opzionali. Nessun argomento pu ricevere pi di un valore alla volta.
Ecco un esempio che non funziona a causa di questa restrizione:
>>>deffunction(a):
...pass
...
>>>function(0,a=0)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
TypeError:function()gotmultiplevaluesforkeywordargument'a'
Quando un parametro formale finale nella forma **nome presente, esso riceve un dizionario (vedere
Mapping Types dict) contenente tutti gli argomenti-chiave, ad eccezione di quelle corrispondenti al
parametro formale. Questo pu essere combinato con un parametro nella forma *nome (descritto nella
prossima sezione) che riceve una tupla contenente gli argomenti posizionali oltre la lista dei parametri
formali. (*nome deve venire prima di **nome) Ad esempio, se si definisce una funzione come questa:
defformaggi(tipo,*argomenti,**chiavi):
print(Avetedel,tipo,?)
print(Midispiace,finitoil,tipo)
forarginargomenti:
print(arg)
print(*40)
chiavi=sorted(chiavi.keys())
forChinkeys:
print(Ch,:,chiavi[Ch])
cliente:Arturo
negoziante:Filippo
scena:Negoziodiformaggi
Si noti che l'elenco dei nomi degli argomenti-chiave, viene creato ordinando il risultato con il metodo
sorted(). Se questo metodo non viene utilizzato,il suo contenuto, sar restituito in modo indefinito.
argomenti posizionali.
>>>defconcatena(*args,sep="/"):
...returnsep.join(args)
...
>>>concatena("terra","marte","venere")
'terra/marte/venere'
>>>concatena("terra","marte","venere",sep=".")
'terra.marte.venere'
...
>>>f=incrementatore(42)
>>>f(0)
42
>>>f(1)
43
C precedente utilizza un'espressione lambda per restituire una funzione. Un altro utilizzo quello di
passare una piccola funzione come argomento:
>>>coppia=[(1,'uno'),(2,'due'),(3,'tre'),(4,'quattro')]
>>>coppia.sort(key=lambdacoppia:coppia[1])
>>>coppia
[(2,'due'),(3,'tre'),(4,'quattro'),(1,'uno')]
Nota del traduttore:
Questo argomento, non trattato in modo esaustivo e/o chiaro nella guida originale. Per cui non essendo
in grado di tradurla e spiegarla in maniera ampia, mi rimetto alla mera traduzione. Comunque in una
eventuale prossima release di questa guida, mi riservo di spiegarlo in modo pi chiaro aggiungendovi
concetti ed esempi.
La prima riga deve sempre essere una orientata alla finalit dell'oggetto. Per brevit, si intende che
non deve indicare esplicitamente il nome o il tipo di oggetto, dal momento che queste informazioni
sono disponibili con altri mezzi (tranne se il nome sembra essere un verbo che descrive il
funzionamento di una funzione). Questa linea dovrebbe iniziare con una lettera maiuscola e
terminare con un punto.
Se vi sono pi righe nella stringa documentazione, la seconda dovrebbe essere vuota, per separare
visivamente il sommario dal resto della descrizione.
Le seguenti righe devono essere uno o pi paragrafi che descrivono le convenzioni di chiamata
dell'oggetto, i suoi effetti collaterali, e quant'altro.
Il parser di Python cio quello strumento facente parte dell'interprete che si occupa di capire cosa
abbiamo scritto e se lo abbiamo scritto bene, non toglie le identazioni dalle stringhe letterali, in modo che
gli strumenti che si occupano della documentazione possano o meno identare a seconda che lo si desideri
o no. Questo viene reso possibile utilizzando la seguente convenzione:
La prima riga non vuota dopo la prima riga della stringa determina la quantit di rientro per
l'intera stringa di documentazione. (Non possiamo usare la prima linea dal momento che
generalmente adiacente all'apertura delle virgolette della stringa per cui il suo rientro non sarebbe
evidente.) Gli spazi "equivalenti" a tale indentazione vengono poi tolti dall'inizio di tutte le linee
della stringa.
Linee non identate correttamente, non dovrebbero esserci, ma se ci si verificasse, tutti i loro spazi
principali dovrebbero essere tolti.
L'equivalenza degli spazi dovrebbe essere testata dopo l'applicazione delle tabulazioni (a 8 spazi,
normalmente).
Note:
[1] In realt, la chiamata per riferimento all'oggetto sarebbe una descrizione migliore, dato che se viene
passato un oggetto mutabile, il chiamante vedr le eventuali modifiche fatte ad esso (gli elementi
inseriti in una lista).
5. Strutture di Dati.
Questo capitolo descrive alcune cose che sono gi state affrontate precedentemente ma in modo pi
dettagliato, e aggiunge anche alcune nuove cose.
>>>stack.pop()
6
>>>stack.pop()
5
>>>stack
[3,4]
>>>#flattenalistusingalistcompwithtwo'for'
>>>vec=[[1,2,3],[4,5,6],[7,8,9]]
>>>[numforeleminvecfornuminelem]
[1,2,3,4,5,6,7,8,9]
Una comprensione di lista, pu contenere espressioni complesse e funzioni nidificate:
>>>frommathimportpi
>>>[str(round(pi,i))foriinrange(1,6)]
['3.1','3.14','3.142','3.1416','3.14159']
...trasposto_riga.append(riga[i])
...trasposto.append(trasposto_riga)
...
>>>trasposto
[[1,5,9],[2,6,10],[3,7,11],[4,8,12]]
Nella pratica, si dovrebbero preferire funzioni precostituite per situazioni complesse. La funzione zip()
per esempio fa un grande lavoro in questa situazione riducendo inoltre la possibilit di errore:
>>>list(zip(*matrice))
[(1,5,9),(2,6,10),(3,7,11),(4,8,12)]
vedere anche Unpacking Argument Lists per maggiori dettagli sull'asterisco della prima linea.
Per instanziare una tupla, basta assegnare una serie di valori separati da una virgola:
>>>t=12345,54321,'salve!'
>>>t[0]
12345
>>>t
(12345,54321,'salve!')
>>>#letuplepossonoesserenidificate:
...u=t,(1,2,3,4,5)
>>>u
((12345,54321,'salve!'),(1,2,3,4,5))
>>>#letuplesonoimmutabili:
...t[0]=88888
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
TypeError:'tuple'objectdoesnotsupportitemassignment
>>>#buttheycancontainmutableobjects:
...v=([1,2,3],[3,2,1])
>>>v
([1,2,3],[3,2,1])
Come si pu notare, la stampa delle tuple viene sempre rappresentata fra parentesi tonde, questo per fare
in modo che si possano interpretare meglio eventuali tuple annidate. Le tuple possono essere create anche
senza le parentesi tonde anche se spesso sono necessarie in processi pi complessi. Non possibile fare
assegnamenti ai singoli elementi di una tupla, tuttavia possibile creare tuple che contengono oggetti
mutabili, come le liste (veramente potente).
Sebbene le tuple possono sembrare simili alle liste, sono spesso utilizzate in situazioni diverse e per scopi
diversi. Le tuple sono immutable (immutabili), e di solito contengono una sequenza eterogenea di
elementi a cui si accede tramite l'estrazione (vedere pi avanti in questa sezione) o d'indicizzazione (o
anche l'attributo nel caso di namedtuples). Le liste sono mutable (mutabili), e i loro elementi di solito
sono omogenei e sono accessibili scorrendo l'elenco.
Un problema particolare la costruzione di tuple contenenti 0 o 1 elementi: la sintassi contiene alcune
stranezze. Tuple vuote vengono costruite usando una coppia vuota di parentesi; una tupla con un elemento
costruita seguendo un valore con una virgola (non sufficiente a racchiudere un singolo valore tra
parentesi). Brutto, ma efficace. Per esempio:
>>>vuota=()
>>>singola='salve',#notarelavirgolaalseguito.
>>>len(vuota)
0
>>>len(singola)
1
>>>singola
('salve',)#riportataancheinfasedistampa.
'12345, 54321, 'ciao!'sono riuniti nella tupla. E' anche possibile l'operazione inversa:
>>>x,y,z=t
Questo si chiama, in modo abbastanza appropriato, sequenza di spacchettamento e funziona per qualsiasi
sequenza sul lato destro. La sequenza di spacchettamento, richiede che vi siano altrttante variabili sul lato
sinistro del segno uguale (=) per gli elementi della sequenza. Si noti che l'assegnazione multipla in realt
solo una combinazione di impacchettamento su tupla e una sequenza di spacchettamento. La mancanza di
uno o pi elementi a sinistra per lo spacchettamento, provoca un'errore.
>>>a={xforxin'abracadabra'ifxnotin'abc'}
>>>a
{'r','d'}
5.5. Dizionari.
Un altro tipo di dati molto utile integrato in Python il dizionario (vedere Mapping Types dict). I
dizionari si trovano a volte in altri linguaggi come "memorie associative" o "array associativi". A
differenza delle sequenze, che sono indicizzate da una serie di numeri, i dizionari sono indicizzati da
chiavi, che possono essere di qualsiasi tipo immutabile compreso stringhe e numeri. Le tuple possono
essere usate come chiavi se contengono solo stringhe, numeri o tuple; se una tupla contiene un
qualsivoglia oggetto mutabile direttamente o indirettamente, non pu essere giustamente utilizzato come
una chiave. Non possibile utilizzare le liste come chiavi, dal momento che esse possono essere
modificate usando le assegnazioni a indice, assegnazioni suddivisioni, o metodi come append() e
extend().
E 'meglio pensare a un dizionario come un insieme non ordinato di coppie chiave:valore, con il requisito
che le chiavi sono uniche (all'interno di un dizionario). Una coppia di parentesi graffe crea un dizionario
vuoto: {}. L'inserimento di un elenco di coppie chiave:valore all'interno delle parentesi graffe, viene
effettuato separando i valori usando delle virgole. Questo anche il modo in cui i dizionari sono
visualizzati sullo schermo.
Le operazioni principali su un dizionario sono la memorizzazione di un valore con una qualche chiave e
l'estrazione del valore per mezzo della stessa. E 'anche possibile eliminare una chiave:valore con del. Se
si memorizza un valore utilizzando una chiave gi in uso, il vecchio valore associato a tale chiave viene
sostituito. Cercare di estrarre un valore utilizzando una chiave inesistente, genera un'errore.
Utilizzare list(d.keys()) su un dizionario, restituisce un elenco di tutte le chiavi usate nel
dizionario, in ordine arbitrario (se invece volete averlo ordinato, basta usare sorted(d.keys())). [2]
Per verificare se una singola chiave presente nel dizionario, utilizzare la parola chiave in.
Ecco un piccolo esempio sull'uso dei dizionari:
>>>tel={'gigi':4098,'nino':4139}
>>>tel['guido']=4127
>>>tel
{'nino':4139,'guido':4127,'gigi':4098}
>>>tel['gigi']
4098
>>>deltel['nino']
>>>tel['ugo']=4127
>>>tel
{'guido':4127,'ugo':4127,'gigi':4098}
>>>list(tel.keys())
['ugo','guido','gigi']
>>>sorted(tel.keys())
['guido','ugo','gigi']
>>>'guido'intel
True
>>>'gigi'notintel
False
L'istruzione dict() costruisce dizionari direttamente da sequenze di coppie chiave-valore:
>>>dict([('nino',4139),('guido',4127),('giacomo',4098)])
{'nino':4139,'giacomo':4098,'guido':4127}
Inoltre, dict comprehensions possono essere usati per creare dizionari da chiavi arbitrarie e valore d'
espressioni:
>>>{x:x**2forxin(2,4,6)}
{2:4,4:16,6:36}
Quando le chiavi sono semplici stringhe, pi facile specificare le coppie che utilizzano argomenti
chiave:
>>>dict(ale=4139,guido=4127,gianni=4098)
{'ale':4139,'gianni':4098,'guido':4127}
funzione zip().
>>>domanda=['nome','obiettivo','colorepreferito']
>>>risposta=['lancillotto','ilsacrogral','blu']
>>>forq,ainzip(domanda,risposta):
...print('ilvostro{0}?{1}.'.format(q,a))
...
ilvostronome?lancillotto.
ilvostroobiettivo?ilsacrogral.
ilvostrocolorepreferito?blu.
Per un ciclo su una sequenza in senso inverso, prima specificare la sequenza in avanti e poi chiamare la
funzionereversed().
>>>foriinreversed(range(1,10,2)):
...print(i)
...
9
7
5
3
1
Per ordinare con un ciclo una sequenza di dati, utilizzare la funzione sorted(), che restituisce una
nuova lista ordinata lasciando inalterata l'originale.
>>>cestino=['mela','fragole','pera','arancia']
>>>forfinsorted(set(cestino)):
...print(f)
...
arancia
fragole
mela
pera
Per modificare una sequenza si effettua l'iterazione all'interno del ciclo (ad esempio per duplicare alcune
voci), si consiglia di eseguire una copia preventiva. Iterare su una sequenza non implica una copia. La
notazione slice cio suddivisione la rende particolarmente conveniente:
>>>voci=['gatto','finestra','defenestrato']
>>>forwinvoci[:]:#Ciclasuunacopiaslicedell'interalista.
...iflen(w)>6:
...voci.insert(0,w)
...
>>>voci
['defenestrato','finestra','gatto','finestra','defenestrato']
(1,2,3)<(1,2,4)
[1,2,3]<[1,2,4]
'ABC'<'C'<'Pascal'<'Python'
(1,2,3,4)<(1,2,4)
(1,2)<(1,2,1)
(1,2,3)==(1.0,2.0,3.0)
(1,2,('aa','ab'))<(1,2,('abc','a'),4)
Si noti che il confronto oggetti di diversi tipi con < or > ammesso a condizione che gli oggetti abbiano
adeguati metodi di confronto. Ad esempio, i tipi numerici misti vengono confrontati in base al loro valore
numerico, cos 0 uguale a 0.0, ecc Altrimenti, piuttosto che fornire un ordinamento arbitrario,
l'interprete sollever un'eccezione TypeError.
Note:
[1] Altri linguaggi, possono restituire l'oggetto mutato, che permette il metodo del concatenamento, come
inserire d->insert("a")->remove("b")->sort().
[2] Chiamare d.keys() restituir una vista dell'oggetto dizionario. Esso supporta operazioni come
prova l'adesione e iterazione, ma il suo contenuto non indipendente dal dizionario originale - solo
una vista.
6. Moduli.
Se si esce dall'interprete Python e poi vi si rientra, le definizioni introdotte (funzioni e variabili) vengono
perse. Pertanto, se si vuole scrivere un programma pi lungo, meglio usare un editor di testo per gestire
l'input per l'interprete passandogli il file da eseguire invece dell'input diretto. Questo noto come la
creazione di uno script. Inoltre se il programma si allunga, consigliabile dividerlo in pi file per
facilitarne la manutenzione. Se hai scritto una funzione comoda da utilizzare in pi programmi, si
consiglia di salvarla per poi utilizzarla invece che copiarla ogni volta.
Per fare in modo che ci possa essere fatto, Python ha un modo per gestire il tutto. Da la possibilit di
mettere tutto in un file da richiamarlo poi sia in modo interattivo che all'interno di altri file. Tale file si
chiamano moduli. Le definizioni di un modulo possono essere importate in altri moduli o nel modulo
principale (l'insieme di variabili di cui si ha accesso a in uno script eseguito al livello superiore e in
modalit calcolatrice).
Un modulo praticamente non altro che un file contenente definizioni e istruzioni Python. Il nome del
file il nome del modulo con aggiunto il suffisso .py. All'interno di un modulo, il nome del modulo
(come una stringa) disponibile come valore nella variabile globale __name__. Per esempio, usare il
vostro editor di testo preferito per creare un file chiamato fibo.py nella directory corrente con i
seguenti contenuti e salvatelo:
#ModulonumeridiFibonacci.
deffib(n):#seriedinumeriFibonaccifinoadnstampati.
a,b=0,1
whileb<n:
print(b,end='')
a,b=b,a+b
print()
deffib2(n):#seriedinumeriFibonaccifinoadnrestituiti.
risultato=[]
a,b=0,1
whileb<n:
risultato.append(b)
a,b=b,a+b
returnrisultato
Ora immette dall'interprete Python il seguente comando:
>>>importfibo
Questo non immette i nomi delle funzioni definite in fibo direttamente nella tabella dei simboli
corrente, immette solo il riferimento al modulo fibo. Facendo riferimento a questo modulo, possibile
usare la funzione in esso contenuta.
>>>fibo.fib(1000)
1123581321345589144233377610987
>>>fibo.fib2(100)
[1,1,2,3,5,8,13,21,34,55,89]
>>>fibo.__name__
'fibo'
Notare che la funzione fib, viene richiamata dal modulo fibo con la notazione del punto
(fibo.fib). In effetti il modulo viene tratto in Python come una classe a tutti gli effetti, anzi per essere
pi precisi come un'oggetto. Questo argomento verr ripreso pi avanti in questa guida.
Se avete intenzione di usare spesso una funzione possibile assegnargli un nome locale:
>>>fib=fibo.fib
>>>fib(500)
1123581321345589144233377
possibile rendere il file utilizzabile come un script cos anche come un modulo importabile, questo
perch il codice che analizza la riga di comando viene eseguito solo se nel file modulo viene eseguito
"main":
verifichiamolo meglio con una prova. In questo caso il modulo viene eseguito.
$pythonfibo.py50
112358132134
Se il modulo importato, in questo caso il codice non viene eseguito:
>>>importfibo
>>>
Questo spesso utilizzato sia per fornire una comoda interfaccia utente per un modulo, o per scopi di test
(che eseguono il modulo come uno script esegue una serie di test).
Quando ricompila il modulo che viene caricato direttamente dalla riga di comando.
Quando c' il modulo di origine.
Per il supporto a una distribuzione senza sorgente (solo compilato), il modulo compilato deve essere nella
directory dei sorgenti, e non ci deve essere un modulo di origine.
Alcuni consigli per i pi esperti:
possibile utilizzare l'opzione -O o -OO per attivare il comando Python che riduce le
dimensioni di un modulo compilato ottimizzando le risorse. L'opzione -O rimuove tutte le
affermazioni proprie delle dichiarazioni, L'opzione -OO rimuove sia le affermazioni delle
dichiarazioni che la documentazione togliendo le stringhe __doc__. Poich alcuni
programmi possono fare assegnamento sulla loro disposizione, si consiglia di utilizzare
questa opzione solo se si sa cosa si sta facendo. I moduli "ottimizzati", hanno un
suffisso . Pyo invece che . Pyc e di solito sono pi piccoli. Le versioni future potrebbero
cambiare il modo con cui viene eseguita l'ottimizzazione.
Un programma non viene eseguito pi velocemente quando viene letto da un file pyo o pyc
rispetto a quando viene letto da un file py. L'unica cosa che pi veloce su pyc o pyo la
velocit con cui sono caricati i files. Questa possibilit va usata solo per programmi di
dimensione veramente grande. Questo pu tornare utile quando si lavora in rete, mentre in
stand alone con la velocit delle attuali macchine il tutto perde di senso.
Il modulo compileall (compila tutto) pu creare file con estensione .Pyc (o .Pyo file
quando viene usato -O o -OO) per tutti i moduli in una directory.
Per maggiori dettagli su questo processo, compreso un diagramma di flusso delle decisioni,
dare un'occhiata a PEP 3147.
>>>sys.ps1='MioPrompt:'
MioPromptprint('Yuck!')
Yuck!
MioPrompt:
Queste due variabili sono funzionali all'interprete solo in modalit interattiva (in altri contesti sarebbe un
non senso).
La variabile sys.path una lista di stringhe che determina il percorso di ricerca dei moduli. Questa
viene inizializzata ad un percorso predefinito facendo riferimento alla variabile d'ambiente
PYTHONPATH, o da una precostituita se PYTHONPATH non impostata. possibile apportare
modifiche usando le operazioni standard permesse con le liste:
>>>importsys
>>>sys.path.append('/usr/pippo/lib/python')
'min','next','object','oct','open','ord','pow','print',
'property',
'quit','range','repr','reversed','round','set','setattr',
'slice',
'sorted','staticmethod','str','sum','super','tuple','type',
'vars',
'zip']
sound/livelloaltodelpackage
__init__.pyInizializzazionedelpackagesound
formats/Sottopackageperifilediconversione
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/Sottopackageperglieffettisuono
__init__.py
echo.py
surround.py
reverse.py
...
filters/Sottopackageperifiltri
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
Quando si importa un package, Python cerca attraverso le directory in sys.path le sotto directory del
package. I file __init__.py permettono a Python di trattare le directory come contenitori di packages,
questo viene fatto per evitare che directory con un nome stringa in comune, nascondano
involontariamente moduli validi che si verificano in seguito nel percorso di ricerca del modulo. Nel caso
pi semplice, __init__.py pu essere solo un file vuoto, ma pu anche eseguire codice di
inizializzazione per il pacchetto o impostare la variabile __all__ come descritto pi avanti.
Gli utenti del package possono importare singoli moduli del package, per esempio:
importSound.Effects.echo
Questo carica il modulo Sound.Effects.echo che deve essere referenziato con il suo nome completo.
sound.effects.echo.echofilter(input,output,delay=0.7,atten=4)
Un modo alternativo per importare il sotto-modulo :
fromSound.Effectsimportecho
Questo comando, carica il sotto-modulo echo, e lo rende disponibile senza il prefisso del pacchetto, in
modo che possa essere utilizzato come segue:
echo.echofilter(input,output,delay=0.7,atten=4)
Ancora un'altra variante quella di importare la funzione o la variabile desiderata direttamente:
fromSound.Effects.echoechofilterimport
Di nuovo, questo carica il sotto-modulo echo, ma rende la sua funzione echofilter () direttamente
disponibile:
echofilter(input,output,delay=0.7,atten=4)
Come si vede, Python mette a disposizione molte strade per ottenere la stessa cosa! Questo fa di Python
un linguaggio potente, semplice e personalizzabile. Cosa chiedere di pi.
Si noti che quando si usa from package import voce, l'elemento pu essere o un modulo (sub
package del pacchetto), o qualche altro nome definito nel package, come una funzione, una classe o una
variabile. I primi test sulle istruzione import vengono fatti per verificare se l'elemento definito
all'interno del pacchetto, se cos non , allora si presuppone che sia un modulo e tenta di caricarlo. Se non
riesce a trovarlo, un'eccezione ImportError viene sollevata.
Al contrario, quando si usa una sintassi del tipo import voce.sottovoce.sottosottovoce,
ogni elemento eccetto l'ultimo deve essere un pacchetto, l'ultimo elemento pu essere un modulo o un
package ma non pu essere una classe o una funzione o una variabile definita nel punto precedente .
superiore coinvolti nell'importazione. Dal modulo surround per esempio, possibile utilizzare:
from.importecho
from..importformats
from..filtersimportequalizer
Si noti che le relative import, si basano sul nome del modulo corrente. Poich il nome del modulo
principale sempre "__main__", moduli, impiegati come il modulo principale di una applicazione
Python devono sempre utilizzare import assoluti.
7. Input e Output.
Esistono diversi modi per mostrare l'output di un programma; i dati possono essere stampati in una forma
leggibile, o scritti in un file per un uso futuro. Questo capitolo tratter alcune possibilit.
il primo modo quello di fare tutto con la gestione delle stringhe; tramite operazioni di divisione
e di concatenazione con ci possibile creare qualsiasi presentazione che si possa immaginare. Il
tipo stringa ha alcuni metodi che eseguono operazioni utili per la formattazione in considerazione
di una determinata larghezza di colonna, che saranno discusse a breve.
Una questione rimane, naturalmente: come si fa a convertire i valori in stringhe? Fortunatamente, Python
ha un modo per convertire qualsiasi valore in una stringa, passando alle funzioni repr() o str() Il
controllo dell'output.
La funzione str() concepita per restituire una rappresentazione dei valori che sono abbastanza
leggibili, mentre repr() destinata a generare rappresentazioni che possono essere lette dall'interprete
(che provocano l'eccezione Syntax Error se non c' una sintassi equivalente). Per gli oggetti che non
hanno una rappresentazione particolare per il contesto, str() restituir lo stesso valore di repr().
Molti valori, come numeri strutture o liste e dizionari, mostrano la stessa rappresentazione utilizzando la
funzione Strings, in particolare, hanno due distinte rappresentazioni.
Ecco alcuni esempi:
>>>s='Ciaomondo.'
>>>str(s)
'Ciaomondo.'
>>>repr(s)
"'Ciaomondo.'"
>>>str(1/7)
'0.14285714285714285'
>>>x=10*3.25
>>>y=200*200
>>>s='Ilvaloredix'+repr(x)+',ediy'+repr(y)+
'...'
>>>print(s)
Ilvaloredix32.5,ediy40000...
>>>#repr()aggiungeallastringalevirgoletteelabarrarovescia
...hello='Ciaomondo\n'
>>>hellos=repr(hello)
>>>print(hellos)
'Ciaomondo\n'
>>>#L'argomentodirepr()puessereunoggettoPython
...repr((x,y,('spam','uova')))
"(32.5,40000,('spam','uova'))"
Questi sono due modi per scrivere un tabella di quadrati e cubi:
1 modo
>>>forxinrange(1,11):
...print(repr(x).rjust(2),repr(x*x).rjust(3),end='')
...#Notarel'usodi'end'sullaprecedentelinea
...print(repr(x*x*x).rjust(4))
...
111
248
3927
41664
525125
636216
749343
864512
981729
101001000
2 modo
>>>forxinrange(1,11):
...print('{0:2d}{1:3d}{2:4d}'.format(x,x*x,x*x*x))
...
111
248
3927
41664
525125
636216
749343
864512
981729
101001000
Si noti che nel primo esempio, che uno spazio tra ogni colonna che stata aggiunto dal metodo print()
il quale, aggiunge sempre gli spazi tra i suoi argomenti.)
Questo esempio illustra il metodo str.rjust() per gli oggetti stringa, che giustifica a destra una
stringa in un campo di una data ampiezza riempiendola di spazi a sinistra. Esistono metodi complementari
str.ljust() e str.center(). Questi metodi non scrivono nulla, ma restituiscono una nuova
stringa formattata. Se la stringa di input troppo lunga, non viene troncata ma restituita intatta; questa
scelta permette di non perdere dati a scapito di una formattazione che potrebbe non avere senso. Ma se lo
scopo quello di troncare comunque, sempre possibile utilizzate la funzione di divisione del tipo
x.ljust(n)[:n].C' un altro metodo, str.zfill(), che formatta una stringa numerica sulla
sinistra con zeri. La si capisce in merito a segni pi e meno:
>>>'12'.zfill(5)InputeOutput
'00012'
>>>'3.14'.zfill(7)
'003.14'
>>>'3.14159265359'.zfill(5)
'3.14159265359'
L'aspetto nell'uso base del metodo str.format() si presenta cos:
>>>print('Noisiamoi{}chedicono"{}!"'.format('cavalieri',
'Ni'))
Noisiamoicavalierichedicono"Ni!"
Le parentesi e i caratteri al loro interno (chiamati campi di formato) vengono sostituiti con gli oggetti
passati nel metodo str.format(). Un numero tra parentesi graffe pu essere usato per riferirsi alla
posizione dell'oggetto passato al metodo str.format().
>>>print('{0}e{1}'.format('pancetta','uova'))
pancettaeuova
>>>print('{1}e{0}'.format('pancetta','uova'))
uovaepancetta
Se argomenti di parole chiave vengono utilizzati nel metodo str.format(), i loro valori sono indicati
utilizzando il nome dell'argomento.
>>>print('Questo{bevanda}{aggettivo}.'.format(
...bevanda='vino',aggettivo='veramentebuono'))
Questovinoveramentebuono.
Argomenti posizionali e parole-chiave possono essere combinati in modo arbitrario.
>>>print('Lavitadi{0},{1},e{altro}.'.format('Gianni',
'Alfredo',altro='Giorgio'))
LavitadiGianni,AlfredoeGiorgio.
Le seguenti forme contratte, possono essere utilizzate per convertire i valori prima della formattazione;
'!a' (applica ascii()), '!s' (applica str()) e '!r' (applica repr()) possono essere usati per
convertire il valore prima della formattazione:
>>>importmath
>>>print('IlvalorediPIapprossimato{}.'.format(math.pi))
IlvalorediPIapprossimato3.14159265359.
>>>print('IlvalorediPIapprossimato{!r}.'.format(math.pi))
IlvalorediPIapprossimato3.141592653589793.
Un ':' opzionale seguito da una formattazione specifica, permette un maggiore controllo sul modo in
cui il valore formattato. L'esempio seguente arrotonda Pi a tre cifre dopo la virgola.
>>>importmath
>>>print('IlvalorediPIapprossimativamente
{0:.3f}.'.format(math.pi))
IlvalorediPIapprossimativamente3.142.
Passando un intero dopo il ':'far s che il campo sia un numero minimo di caratteri estesi. Questo
utile per fare tabelle ben formattate.
>>tabella={'Alfredo':4127,'Gianni':4098,'Andrea':7678}
>>>fornome,telefonointabella.items():
...print('{0:10}==>{1:10d}'.format(nome,telefono))
...
Gianni==>4098
Andrea==>7678
Alfredo==>4127
Se si ha una stringa di formato davvero lunga che non si vuole dividere, sarebbe bello se si potesse fare
riferimento alle variabili da formattare per nome invece che per posizione. Questo pu essere fatto
semplicemente passando il dizionario e utilizzando le parentesi quadre '[]' per accedere alle chiavi.
>>>tabella={'Alfredo':4127,'Gianni':4098,'Andrea':8637678}
>>>print('Gianni:{0[Gianni]:d};Alfredo:{0[Alfredo]:d};'
...'Andrea:{0[Andrea]:d}'.format(tabella)
Gianni:4098;Alfredo:4127;Andrea:8637678
Ci potrebbe essere fatto anche passando la tabella come argomenti chiave con la notazione '**'.
>>>tabella={'Alfredo':4127,'Gianni':4098,'Andrea':8637678}
>>>print('Gianni:{Gianni:d};Alfredo:{Alfredo:d};Andrea:
{Andrea:d}'.format(**table))
Gianni:4098;Alfredo:4127;Andrea:8637678
Ci particolarmente utile in combinazione con la funzione precostituita vars(), che restituisce un
dizionario contenente tutte le variabili locali.
Come si potuto notare, Python possiede una capacit di formattazione dell'output veramente notevole
che permette buoni risultati estetici con poca fatica. Tutto questo utile per formattazioni su schermo a
linea di comando oppure per la scrittura su file, ma perdere un po' di valore quando Python viene
utilizzato con interfacce grafiche le quali si occupano in prima persona della formattazione dei vari
campi.
Per una panoramica completa sulla formattazione delle stringhe usando str.format() , fare
riferimento a Format String Syntax.
'r'- Il file sar aperto in modalit testo solo in lettura. Questa la modalit predefinita se
nessuna modalit viene specificata.
'w'- Il file sar aperto nella sola modalit testo solo in scrittura. Se esiste un file con lo stesso
nome, esso sar sovrascritto.
'a'- Il file sar aperto in modalit testo aggiungendo alla fine tutto ci che verr scritto.
'r+'- Il file sar aperto in modalit lettura/scrittura.
'modalita' + 'b'- Se aggiunta alle altre modalit descritte, l'opzione 'b', aprir il file in
modalit binaria, in questo caso i dati vengono letti e scritti sotto forma di oggetti byte. Questa
modalit dovrebbe essere utilizzata per tutti i file che non contengono testo.
Siccome il marcatore di fine file cambia in base alla piattaforma (\n su Unix/Linux \ r \ n su Windows)
Python apre i file in lettura e usa come marcatore di fine file quello di Unix/Linux cio \n . Quando il file
invece viene scritto, Python converte il carattere di fine file nella piattaforma specifica in modo
automatico. Quindi se un file viene letto e scritto sotto Windows quando verr chiuso il terminatore di
file ritorner \ r \ n . Questo modo di gestire il terminatore di file garantisce la portabilit sulle
piattaforme ma pone un potenziale rischio e cio: il rischio di corrompere file di tipo non testo cio
JPEG, EXE ed altri di tipo binario per esempio. State molto attenti a utilizzare la modalit binaria
durante la lettura e la scrittura di questi file.
>>>f.read()
'Questol'interofile.\n'
>>>f.read()
''
L'istruzione f.readline(), legge una singola riga del file comprensiva del carattere (\n) che viene
lasciato alla fine della stringa, e viene omesso solo nell'ultima riga del file se il file non termina con un
ritorno a capo. Questo disambigua il valore restituito, infatti se f.readline() restituisce una stringa
vuota, significa che la fine del file stata raggiunta, mentre se una riga bianca rappresentata da ' \n',
cio una stringa contenente un solo '\n'.
>>>f.readline()
'Questalaprimalineadelfile.\n'
>>>f.readline()
'Secondalineadelfile\n'
>>>f.readline()
''
Per leggere delle linee da un file, si pu eseguire un ciclo sull'oggetto file. Questa tecnica veloce utilizza
in mode efficiente la memoria e richiede poco codice esempio:
>>>forlineinf:
...print(line,end='')
...
Questalaprimalineadelfile.
Secondalineadelfile
Se volete leggere tutte le linee del file in una lista potete usare anche list(f) o f.readlines().
La funzione f.write(stringa)scrive tutto il contenuto di stringa sul file e restituisce il numero
di caratteri scritto.
>>>f.write('Questountest\n')
16
Notare che il valore restituito, non comprensivo del marcatore di fine linea. Per scrivere qualcosa di
diverso da una stringa, deve essere prima convertito in una stringa:
>>>valore=('unarisposta',42)
>>>s=str(valore)
>>>f.write(s)
20
Notare che il valore restituito, comprensivo di tutto anche delle parentesi tonde. f.tell() restituisce
un intero che fornisce il numero di byte dell'oggetto file misurati dall'inizio del file.
Per variare la posizione dell'oggetto file si usi f.seek(offset, da_cosa). La posizione viene
calcolata aggiungendo ad offset un punto di riferimento, selezionato tramite l'argomento da_cosa. Un
valore di da_cosa pari a 0 effettua la misura dall'inizio del file, 1 utilizza come punto di riferimento la
posizione attuale, 2 usa la fine del file. da_cosa pu essere omesso ed il suo valore predefinito pari a
0, viene quindi usato come punto di riferimento l'inizio del file.
>>>f=open('mio_file','rb+')
>>>f.write(b'0123456789abcdef')
16
>>>f.seek(5)#Vaal6bytedelfile.
5
>>>f.read(1)
b'5'
>>>f.seek(3,2)#Vaal3byteprimadellafine.
13
>>>f.read(1)
b'd'
I file di testo (quelli aperti, senza la b nella stringa di modalit) ammettono solo ricerche relative
dall'inizio del file (ad eccezione di cercare dalla fine di file con seek(0, 2)), e gli unici valori validi
sono quelli restituiti da f.tell(). Qualsiasi altro valore di scostamento produce un comportamento
indefinito. Quando si finisce di lavorare con un file, bisogna chiamare f.close() per chiudere il file e
scrivere i dati eventualmente presenti nel buffer di memoria su disco, e liberare le risorse. Ogni successivo
tentativo di lavorare con esso generer un'eccezione.
>>>f.close()
>>>f.read()
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
ValueError:I/Ooperationonclosedfile
Quando si lavora con i file, un buon sistema l'utilizzo del metodo with. Questo ha il vantaggio che il
file verr chiuso correttamente dopo aver finito il suo lavoro anche nel caso in cui nel frattempo si generi
un'eccezione. La scrittura del suo codice inoltre molto pi compatta rispetto all'equivalente del blocco
try-finally.
>>>withopen('file_lavoro','r')asf:
...dati_letti=f.read()
>>>f.closed
True
Gli oggetti file hanno alcuni metodi addizionali, come isatty() e truncate(), che sono utilizzati
meno frequentemente, consultare la Reference Library per una guida completa agli oggetti file.
Se avete un' oggetto X per esempio, potete vedere in una stringa il contenuto con una semplice linea di
codice:
>>>json.dumps([1,'semplice','lista'])
'[1,"semplice","lista"]'
Una variante della funzione dumps() chiamata dump(), semplicemente serializza l'oggetto
codificandolo in un file di testo( text file). Quindi se f un file oggetto di testo, aprendolo in scrittura
possibile fare questo:
json.dump(x,f)
Per decodificare nuovamente l'oggetto, se f un oggetto file di testo che stato aperto per la lettura:
x=json.load(f)
Questa semplice tecnica di serializzazione in grado di gestire liste e dizionari, ma la serializzazione di
istanze di classi arbitrarie in JSON richiede uno sforzo in pi. Riferimenti al modulo json contengono
una spiegazione a questo.
Il modulo pickle , contrariamente a JSON, un protocollo che consente la serializzazione di oggetti
Python arbitrariamente complessi. Come tale, specifico solo per Python e non pu essere utilizzato per
comunicare con applicazioni scritte in altri linguaggi. E 'anche insicuro per definizione! Deserializzare
dati pickle provenienti da una fonte non attendibile pu eseguire pericolosamente codice arbitrario, se i
dati sono stati realizzati da un cracker esperto.
8. Errori ed Eccezioni.
Fino ad ora i messaggi di errore sono stati solo accennati, ma se avete provato gli esempi probabilmente
ne avrete fatti alcuni. Ci sono (almeno) due tipi di errori: errori di sintassi e di logica.
8.2. Eccezioni.
Anche se una dichiarazione o un'espressione sono sintatticamente corrette, pu avvenire un errore quando
si tenta di eseguirla. Gli errori rilevati durante l'esecuzione sono chiamati eccezioni e sono spesso errori
di logica, ma potrebbero riferirsi anche all'esaurimento della memoria o lo spazio su disco ecc. A volte
sono fatali terminando senza troppi complimenti il programma o addirittura bloccare il calcolatore.
Fortunatamente impareremo a gestirli al meglio. Tuttavia la maggior parte delle eccezioni sono gestite dal
programma e possono produrre messaggi di errore come illustrato di seguito:
>>>10*(1/0)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
ZeroDivisionError:divisionbyzero
>>>4+spam*3
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
NameError:name'spam'isnotdefined
>>>'2'+2
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
TypeError:Can'tconvert'int'objecttostrimplicitly
L'ultima riga del messaggio di errore indica che cosa accaduto. Le eccezioni sono di diversi tipi, e il tipo
viene stampato come parte del messaggio: i tipi nell'esempio sono ZeroDivisionError,
NameError e TypeError. Questo vero per tutte le eccezioni precostituite, ma non lo per le
eccezioni definite dall'utente (anche se una convenzione utile). I nomi delle eccezioni standard sono
identificatori predefiniti. Non sono parole riservate. Il resto della linea fornisce dettagli in base al tipo di
eccezione e che cosa l'ha causata.
La parte antecedente del messaggio di errore mostra il contesto in cui avvenuta l'eccezione, nella forma
di una traccia dello stack. In generale, esso contiene una traccia che elenca le linee del sorgente, tuttavia,
non visualizzer le linee lette dallo standard input.
Note:
Built-in Exceptions elenca le eccezioni precostituite e il loro significato.
...x=int(input("Immettiunnumerointero:"))
...break
...exceptValueError:
...print("Uhm!Questononunnumerovalido.Ritenta...")
...
L'istruzione try lavora come segue.
1: try facente parte del blocco try e except.
2: Se non si verificano errori la clausola except non viene eseguita e il programma prosegue
oltre terminando il test di try .
3: Se un'eccezione viene sollevata durante l'esecuzione di try, le rimanenti istruzione nel blocco
vengono saltate. Se l'eccezione coincide con except, allora except viene eseguita e poi
l'esecuzione continua dopo l'istruzione try.
4: Se si verifica un'eccezione che non corrisponde a quella citata nella clausola except, si passa a
istruzioni try pi esterne, cio per esempio alla funzione di un blocco chiamante e se non viene
trovato alcun gestore, la gestione passa a Python e l'esecuzione si ferma visualizzando un
messaggio come mostrato sopra terminando il programma.
Un'istruzione try pu avere pi di una clausola except, per specificare pi gestori per diverse eccezioni,
ma solo uno di essi verr eseguito. I gestori si occupano solo delle eccezioni che si verificano nella
clausola try corrispondente, non in altri gestori della stessa istruzione try. Una clausola di eccezione pu
nominare pi di un'eccezione come fosse un tupla tra parentesi. Per esempio:
...except(RuntimeError,TypeError,NameError):
...pass
Nell'ultima clausola except si pu omettere il nome o i nomi utilizzandola come come caratteri jolly nel
contesto. Questa pratica, da utilizzare con estrema cautela in quanto facile mascherare un errore di
programmazione vero e proprio in questo modo! Pu anche essere utilizzato per stampare un messaggio di
errore e quindi risollevare l'eccezione (permettendo ad una procedura chiamante di gestire l'eccezione):
Una buona pratica di programmazione anche se un po' tediosa, quella di creare un file di Log su cui
scrivere il tipo di errore avvenuto e in che parte del programma. Questo permette la rapida correzione
dello stesso su programmi distribuiti.
importsys
try:
f=open('mio_file.txt')
s=f.readline()
i=int(s.strip())
exceptIOErroraserr:
print("erroreI/O:{0}".format(err))
exceptValueError:
print("Impossibileconvertireildatoinunintero.")
except:
print("Erroreinaspettato:",sys.exc_info()[0])
raise
Con il blocco try ... except , possibile utilizzare anche la clausola opzionale else, che, quando
presente, deve seguire la clausola except. E' utile quando il codice che deve essere eseguito non
soggetto ad una nuova eccezione sollevata da try. Per esempio:
forarginsys.argv[1:]:
try:
f=open(arg,'r')
exceptIOError:
print('impossibileaprire.',arg)
else:
print(arg,'has',len(f.readlines()),'lines')
f.close()
L'uso della clausola else preferibile all'aggiunta di codice supplementare alla clausola try poich evita
l'intercettazione accidentale di un'eccezione che non stata sollevata dal codice protetto dal blocco try ...
except.
Un'eccezione, pu avere un valore associato, conosciuto anche come argomento dell'eccezione. La
presenza e il tipo dell'argomento dipendono dal tipo di eccezione.
La clausola except, pu specificare una variabile dopo il suo nome. Questa variabile legata all'istanza
dell'eccezione con argomenti memorizzati in instance.args. Per comodit, l'eccezione definisce
__str__() in modo che gli argomenti possono essere stampati direttamente senza dover fare
riferimento ad .args. Se si desidera, anche possibile lanciare un'eccezione con l'istruzione raise
aggiungendo gli attributi desiderati.
>>>try:
...raiseException('fagioli','uova')
...exceptExceptionastipo:
...print(type(tipo))#L'istanzadell'eccezione.
...print(tipo.args)#Gliargomenticontenutiin.args.
...print(tipo)#__str__permettelastampadiargs.
...#mapuesseresovrascrittoinexception.
...x,y=tipo.args#scompattaargs.
...print('x=',x)
...print('y=',y)
...
<class'Exception'>
('fagioli','uova')
('fagioli','uova')
x=pancetta
y=uova
Se un'eccezione ha argomenti, questi vengono stampati come ultima parte ('il dettaglio') del messaggio
per le eccezioni non gestite.
I gestori delle eccezioni non si occupano solo delle eccezioni gestite dal blocco try ... except, ma anche
di tutti quegli errori che si possono verificare in qualsiasi parte del programma in quanto Python che
utilizzando il blocco try ... except al suo interno, li gestisce al meglio anche in quelle funzioni che
vengono chiamate indirettamente. Per esempio:
>>>defquesta_fallisce():
...x=1/0
...
>>>try:
...questa_fallisce()
...exceptZeroDivisionErroraserrore:
...print('Gestioneerrorediesecuzione:',errore)
...
Gestioneerrorediesecuzione:intdivisionormodulobyzero
Classes per saperne di pi sulle classi Python). Le eccezioni dovrebbero normalmente essere derivate
dalla classe Exception, direttamente o indirettamente. Per esempio:
>>>classMioErrore(Exception):
...def__init__(self,value):
...self.value=value
...def__str__(self):
...returnrepr(self.value)
...
>>>try:
...raiseMioErrore(2*2)
...exceptMioErrorease:
...print('Lamiaeccezione,valore:',e.value)
...
Lamiaeccezione,valore:4
>>>raiseMioErrore('oops!')
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
__main__.MioErrore:'oops!'
In questo esempio, i valori predefiniti di __init__() e Exception sono stati sovrascritti, per cui il
nuovo comportamento crea semplicemente l'attributo value. Questo sostituisce il comportamento
predefinito di args.
Classi di eccezioni possono essere definite come si pu fare con una qualsiasi altra classe, ma solitamente
esse vengono mantenute semplici. Spesso esse offrono solo una serie di attributi che permettono di
conoscere la natura dell'errore. Quando si crea un modulo che pu sollevare diversi errori distinti, una
pratica comune quello di creare una classe base per le eccezioni definite da quel modulo, e una
sottoclasse per creare specifiche classi di eccezioni per condizioni di errore diverse.
classError(Exception):
"""Classebasepereccezioniinquestomodulo."""
pass
classInputError(Error):
"""Eccezionelanciatasuerrorediinput.
Attributi:
espressioneinputespressionediqualeerroreavvenuto.
MessaggioSpiegazionedell'errore.
"""
def__init__(self,espressione,messaggio):
self.espressione=espressione
self.messaggio=messaggio
classErroreTransizione(Error):
"""Lanciataquandoun'operazionetentaunatransizionechenon
permessa.
Attributi:
precedenteStatoall'iniziodellatransizione.
successivatentativonuovostato.
messaggioSpiegazioneperchlaspecificanonconsentita.
"""
def__init__(self,precedente,successiva,messaggio):
self.precedente=precedente
self.successiva=successiva
self.messaggio=messaggio
La maggior parte delle eccezioni vengono definite con nomi che terminano in "Error" simile alla
denominazione delle eccezioni standard, questo facilita e accellera la comprensione.
Molti moduli standard e non, definiscono le proprie eccezioni per riportare errori che possono verificarsi
nelle funzioni che definiscono. Ulteriori informazioni sulle classi saranno presentate nelle capitolo
Classi .
>>>divide(2,0)
divisioneperzero!
eseguelaclausolafinally
>>>divide("2","1")
eseguelaclausolafinally
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
File"<stdin>",line3,individe
TypeError:unsupportedoperandtype(s)for/:'str'and'str'
Come potete vedere, la clausola finally viene eseguita in ogni caso. Il TypeError sollevato
dividendo due stringhe non viene gestito dalla clausola except e quindi viene rilanciato dopo che la
clausola finally stata eseguita.
Nelle applicazioni del mondo reale, la clausola finally utile per liberare risorse esterne (ad esempio
file, connessioni di rete ecc.), indipendentemente dal fatto che l'uso della risorsa abbia avuto successo.
9. Classi.
Premesso che l'argomento richiederebbe un trattato a se stante, vista la complessit, lo tratteremo qui in
modo sintetico e peculiare a Python. Rispetto ad altri linguaggi di programmazione, il meccanismo delle
classi di Python permette di aggiunge nuove classi con una sintassi e semantica minimi. Si tratta di una
miscela di meccanismi per la manipolazione delle classi che si trovano in C++ e Modula-3 che forniscono
Python di tutte le caratteristiche standard della OOP (Object Oriented Programming). Il meccanismo
dell'ereditariet permette classi di base multiple, e una classe derivata pu sovrascrivere tutti i metodi
della sua classe o della classe da cui deriva, e un metodo pu chiamare il metodo di una classe base con lo
stesso nome. Gli oggetti possono contenere quantit arbitrarie di tipi e dati. Cos come i moduli, le classi
partecipano alla natura dinamica di Python: vengono create in fase di esecuzione, e possono essere
ulteriormente modificate dopo la creazione.
Nella terminologia C++, normalmente i membri di classe (inclusi i membri dati) sono pubblici (tranne le
variabili private (Private Variables) (vedi sotto)), e tutti membri delle funzioni sono virtuali. Le funzioni
virtuali sono il meccanismo con cui si realizza in C++ il polimorfismo, che una delle pi importanti
caratteristiche dei linguaggi orientati agli oggetti, che permette ad oggetti simili di rispondere in modo
diverso agli stessi comandi. Come in Modula-3, non ci sono scorciatoie per riferirsi ai membri
dell'oggetto dai suoi metodi. La funzione di metodo viene dichiarata con un' esplicito primo argomento
che rappresenta l'oggetto, che viene fornito in modo implicito dalla chiamata. Come in Smalltalk, le classi
stesse sono oggetti. Ci fornisce una semantica per l'importazione e la ridenominazione. A differenza di
C++ e Modula-3, tipi precostituiti possono essere utilizzati come classi base per essere estese dall'utente.
Inoltre, sempre come in C + +, operatori precostituiti (operatori aritmetici, indicizzazioni, ecc), possono
essere utilizzati con una sintassi speciale che pu essere ridefinita per istanziare nuove classe.
La mancanza di una terminologia universalmente accettata per parlare di classi, ci porta a paragonare
Python ad altri linguaggi per meglio comprendere ci che viene detto. Questo non significa che Python
non abbia pari potenzialit anzi! Questo si rende necessario perch la programmazione ad oggetti pur
essendo oramai in uso da anni, rimane ostica ai pi specialmente ai neofiti. Quindi paragoni ed esempi si
rendono indispensabili.
nomi sono: l'insieme dei nomi precostituiti (contenenti funzioni come abs () e i nomi delle eccezioni
precostituite), i nomi globali in un modulo, e i nomi locali in una funzione chiamata. In un certo senso
l'insieme degli attributi di un oggetto contribuisce a formare uno spazio dei nomi. La cosa importante da
sapere sugli spazi dei nomi che non c' assolutamente nessuna relazione tra i nomi in diversi spazi dei
nomi, per esempio, due moduli diversi potrebbero entrambi definire una funzione con lo stesso nome
senza confusione, questo possibile anteponendo al nome della funzione il nome del modulo con la
notazione del punto tipo mioModulo.miaFunzione.
A proposito sempre a causa di una mancanza di specifiche precise sulle classi, io uso la parola attributo
per qualsiasi nome che segua un punto per esempio nel z.real, real un attributo dell'oggetto z. A rigor
di termini, i riferimenti a nomi nei moduli sono riferimenti ad attributi come gi detto nel paragrafo
precedente.
Gli attributi, possono essere a sola lettura o scrivibili. In quest'ultimo caso, l'assegnazione di attributi
possibile.
Gli attributi dei moduli sono scrivibili: si pu scrivere nomemodulo.risposta = 42. Gli attributi
scrivibili possono anche essere cancellati con l'istruzione del.
Ad esempio, del nomemodulo.risposta rimuover l' attributo risposta dall'oggetto nominato
nomemodulo.
Gli spazi dei nomi vengono creati in momenti diversi e hanno diverse vite. Lo spazio dei nomi che
contiene i nomi precostituiti viene creato quando l'interprete Python si avvia, e non viene mai eliminato.
Lo spazio dei nomi globale riferiti a un modulo vengono creati quando la definizione del modulo viene
letta; normalmente, gli spazi dei nomi del modulo durano fino a quando l'interprete si chiude. Le
istruzioni eseguite dall'invocazione di livello superiore dell'interprete, lette da un file di script o
interattivamente, sono considerate parte di un modulo chiamato __main__, in modo da avere il proprio
spazio dei nomi globale. (I nomi precostituiti in realt vivono anche in un modulo che si chiama
builtins.)
Lo spazio dei nomi locale per una funzione viene creato quando la funzione viene chiamata, e cancellati
quando la funzione restituisce il suo valore o solleva un'eccezione non gestita all'interno della funzione.
(In realt, la dimenticanza sarebbe uno modo sporco per descrivere meglio ci che effettivamente accade.)
Naturalmente, invocazioni ricorsive hanno ciascuna il proprio spazio dei nomi locale (memoria
permettendo).
Un' ambito, una visibilit che una regione testuale di un programma Python possiede dove uno spazio
accessibile direttamente. "Direttamente accessibile" qui significa che un riferimento qualificato ad un
nome cerca di trovare il nome nello spazio dei nomi opportuno.
Anche se gli ambiti sono determinati staticamente cio che non possono essere modificati, essi sono
utilizzati in modo dinamico. In qualsiasi momento durante l'esecuzione ci sono almeno tre visibilit
annidate cui i spazi sono direttamente accessibili:
L'area pi interna, quella che viene ricercata per prima e contiene i nomi locali.
La visibilit di tutte le funzioni viene ispezionata cercando nello spazio dei nomi pi vicino
contenente il simbolo cercato, fino ad espandere la ricerca verso simboli non locali, ma anche
verso simboli non globali.
l'ambito next-to-last contiene i nomi dei moduli globali attuali.
l'ambito pi esterno (l'ultimo) lo spazio dei nomi che contiene i nomi precostituiti.
Se un nome viene dichiarato globale, allora tutti i riferimenti e le assegnazioni vanno direttamente al
campo centrale che contiene i nomi globali del modulo. Per ricollegare le variabili presenti al di fuori del
proprio ambito, pu essere utilizzata la dichiarazione nonlocal, se non dichiarate non locale, quelle
variabili sono in sola lettura (un tentativo di scrivere su tale variabile sar sufficiente per creare una nuova
variabile locale nel campo di applicazione pi interno, lasciando il nome identico della variabile esterna
invariato).
Di solito, l'ambito locale fa riferimento a nomi locali della (testualmente) funzione corrente. Al di fuori
delle funzioni, l'ambito locale fa riferimento allo stesso spazio dei nomi dell'ambito globale del modulo.
Le definizioni di classe pone un altro spazio dei nomi nell'ambito locale.
E 'importante rendersi conto che gli ambiti sono determinati testualmente: la visibilit globale di una
funzione definita in un modulo lo spazio dei nomi di quel modulo, non importa da dove o da che alias la
funzione viene chiamata. D'altra parte, la ricerca effettiva dei nomi viene fatta dinamicamente in fase di
esecuzione tuttavia, la definizione del linguaggio si sta evolvendo verso la risoluzione dei nomi statici, in
fase di "compilazione", quindi non si basano sulla risoluzione dei nomi dinamici! (In effetti, variabili
locali sono gi determinate staticamente.)
Un cavillo particolare di Python che se nessuna dichiarazione globale ( global ) in essere, le
assegnazioni ai nomi vanno sempre nel perimetro pi interno. Le assegnazioni non copiano dati, ma
creano solo i nomi agli oggetti. Lo stesso vale per le cancellazioni: l'istruzione del x rimuove
l'associazione di x dallo spazio dei nomi a cui fa riferimento l'ambito locale. In realt tutte le operazioni
che introducono nuovi nomi usano l'ambito locale e in particolare, le dichiarazioni di importazione (
import) e le definizioni di funzioni legano il modulo o nome di funzione all'ambito locale.
L'istruzione global pu essere utilizzata per indicare che particolari variabili vivono in ambito globale e
l dovrebbero essere riferite, l'istruzione nonlocal indica che particolari variabili vivono in un ambito
di inclusione e l dovrebbero essere riferite.
Attributi riferimenti: Utilizzano la sintassi standard utilizzata per tutti i riferimenti attributi
in Python; oggetto.nome. Per nomi di attributi validi s'intende tutti i nomi che sono
nello spazio dei nomi della classe quando l'oggetto classe stato creato. Quindi, se la
definizione di classe si presentava cos:
classMiaClasse:
"""Unsempliceesempiodiclasse"""
i=12345
deff(self):
return'Ciaomondo'
Allora MiaClasse.i e MiaClasse.f sono riferimenti validi ai suoi attributi, che
restituiscono rispettivamente un intero ed un oggetto funzione. Gli attributi di classe
possono inoltre essere assegnati in modo da poter cambiare il valore di MiaClasse.i
per assegnamento. __doc__ anch'esso un attributo valido, restituendo la stringa di
documentazione appartenente alla classe, cio "Un semplice esempio di classe".
L'istanzazione di una classe, viene fatta con la notazione delle funzioni. Basta far finta che
l'oggetto di classe una funzione senza parametri per avere una nuova istanza della classe.
Ad esempio (supponendo la precedente classe ad esempio):
x=MiaClasse()
Crea una nuova istanza della classe assegnata all'oggetto x in una variabile locale.
L'operazione di istanziazione crea un oggetto vuoto. Molte classi creano oggetti personalizzati per uno
specifico stato iniziale. Una classe infine pu definire un metodo speciale chiamato__init__() come
questo:
def__init__(self):
self.data=[]
Quando una classe viene definita con il metodo __init__(), l'istanziazione della classe, invoca
automaticamente __init__() per la nuova istanza di classe creata. Per cui in questo esempio, una
nuova istanziazione di classe pu essere ottenuta cos:
x=MiaClasse()
Naturalmente, il metodo __init__() pu avere argomenti, per una maggiore flessibilit. In tal caso, gli
argomenti forniti alla classe vengono passati a__init__(). Per esempio:
>>>classComplessa:
...def__init__(self,partereale,parteimmaginaria):
...self.r=partreale
...self.i=partimmaginaria
...
>>>x=Complessa(3.0,4.5)
>>>x.r,x.i
(3.0,4.5)
Quindi:
Gli attributi di dati, corrispondono alle "variabili d'istanza" in Smalltalk, e ai "dati membro" in C + +. Gli
attributi di dati non necessitano di essere dichiarati come le variabili locali, essi cominciano ad esistere
quando viene fatta la prima assegnazione. Ad esempio, se x l'istanza di MiaClasse creata in
precedenza, il seguente pezzo di codice stamper il valore 16, senza lasciare traccia (notare che x un
valore e quindi va associata al verbo ESSERE):
x.contatore=1
whilex.contatore<10:
x.contatore=x.contatore*2
print(x.contatore)
delx.contatore
L'altro tipo d'attributo d'istanza si riferisce ai metodi. Un metodo una funzione che "appartiene a" un
oggetto. (In Python, il termine metodo non unico a istanze di classi: altri tipi di oggetti possono avere
dei metodi, ad esempio, oggetti lista hanno metodi chiamati append, insert, remove, sort (notare
che tutti fanno qualcosa e quindi vanno associati al verbo FARE) e cos via, detto ci, nella discussione
che segue, useremo il termine metodo esclusivamente per indicare i metodi degli oggetti d'istanza di
classe, se non diversamente specificato.)
Nomi validi per metodi di un'istanza d'oggetto, dipendono dalla sua classe. Per definizione, tutti gli
attributi di una classe che sono oggetti funzionali definiscono metodi corrispondenti alle sue istanze.
Quindi, nel nostro esempio, x.f un riferimento valido ad un metodo, dal momento che MiaClasse.f
una funzione, ma x.i non , in quanto MiaClasse.i non lo . Ma x.f non la stessa cosa di
MiaClasse.f , un oggetto metodo, non un oggetto funzione.
classC:
f=funzione_esterna
defg(self):
return'helloworld'
h=g
Ora f, g e h sono tutti attributi della classe C che si riferiscono ad oggetti funzione, e di conseguenza
sono tutti metodi delle istanze di C essendo h esattamente equivalente a g. Questa pratica, viene di solito
usata per rendere pi difficile la comprensione di un sorgente ad altri programmatori.
I metodi possono chiamare altri metodi usando gli attributi metodo con l'argomento self:
classBag:
def__init__(self):
self.data=[]
defadd(self,x):
self.data.append(x)
defaddtwice(self,x):
self.add(x)
self.add(x)
I metodi possono referenziare nomi globali allo stesso modo come le funzioni ordinarie. La visibilit
globale associata a un metodo il modulo che contiene la sua definizione (Una classe non viene mai usata
con visibilit globale). Mentre non ci sono dei buoni motivi per usare dati globali in un metodo, ci sono
molti usi legittimi della visibilit globale: per dirne una, funzioni e moduli importati in ambito globale
possono essere utilizzati dai metodi, nonch funzioni e classi definite in esso. Di solito, la classe che
contiene il metodo ed essa stessa definita in questo ambito globale. Nella prossima sezione vedremo
alcune buone ragioni per cui un metodo potrebbe voler referenziare la propria classe.
Ogni valore un oggetto, e quindi ha una classe (chiamato anche tipo) e viene memorizzato come
object.__class__.
9.5. L'Ereditariet.
Naturalmente, un linguaggio che supporta le classi senza ereditariet non sarebbe degno di attenzione. La
sintassi per la definizione di una classe derivata (l'ereditariet appunto) si ottiene pi o meno cos:
classNomeClasseDerivata(NomeClasseBase):
<istruzione1>
.
.
.
<istruzionen>
Il nome NomeClasseBase deve essere definito in un ambito che contiene la definizione della classe
derivata. Al posto di un nome di classe base, sono ammesse anche altre espressioni arbitrarie. Ci pu
essere utile, per esempio, quando la classe base definita in un altro modulo:
classe NomeClasseDerivata (nomemodulo.NomeClasseBase)
Esecuzione di una definizione di classe derivata procede nello stesso modo di una classe base. Quando
l'oggetto di classe viene costruito, la classe base viene ricordata. Questo meccanismo viene utilizzato per
risolvere i riferimenti ad attributi: se un attributo richiesto non viene trovato nella classe, la ricerca
procede fino a guardare nella classe base. Questa regola viene applicata ricorsivamente se la classe base a
sua volta derivata da un'altra classe.
Non c' niente di speciale creazione di classi derivate: NomeClasseDerivata() crea una nuova
istanza della classe. I riferimenti ai metodi vengono risolti come segue: l'attributo classe corrispondente
viene cercato, salendo lungo la catena di classi base, se necessario, e il riferimento al metodo valido se
questo produce un oggetto funzione.
Le classi derivate possono sovrascrivere i metodi delle loro classi base. Poich i metodi non hanno
privilegi speciali quando chiamano altri metodi dello stesso oggetto, un metodo di una classe base che
chiama un altro metodo definito nella stessa classe base pu finire per chiamare un metodo di una classe
derivata che lo sovrascrive. (Per i programmatori C + +: tutti i metodi in Python sono effettivamente
virtual (virtuali)).
Generalmente la sovrascrittura di un metodo in una classe derivata, ha lo scopo di estenderne le
funzionalit piuttosto che sostituirlo in toto. Infatti a rigore di logica se a un metodo manca una
funzionalit, lo si sovrascrive aggiungendocela, se invece diverso, se ne crea uno nuovo anche se non
sempre cos. C' un modo semplice per chiamare direttamente il metodo della classe base: basta
chiamare NomeClasseBase.nomemetodo(self, argomenti). Questo talvolta risulta il suo
utilizzo (va detto che questo funziona solo se la classe base accessibile come NomeClasseBase in
ambito globale.)
Python dispone di due funzioni precostituite che funzionano con l'ereditariet:
ereditati da una classe genitore venga cercata scalando in profondit, da sinistra a destra, non cercando
due volte nella stessa classe in cui vi una sovrapposizione nella gerarchia. Cos, se un attributo non
viene trovato in NomeClasseDerivata, la ricerca avviene in ClasseBase1, poi (ricorsivamente)
nelle classi base di ClasseBase2, e se non stato trovato, si cerca in ClasseBase3, e cos via.
In verit, la cosa leggermente pi complessa. La risoluzione dell'ordine di un metodo cambia
dinamicamente per supportare chiamate cooperative a super(). Questo approccio noto in alcune altri
linguaggi con ereditariet multipla come call-next-method ed pi potente della chiamata super
presente in altri linguaggi a ereditariet singola.
L'ordinamento dinamico necessario in quanto tutti i casi di ereditariet multipla mostrano uno o pi
diamond relationships (cio una specie di relazionamento superiore) in cui almeno una delle classi
genitore pu accedere attraverso percorsi multipli della classe pi in basso. Ad esempio, tutte le classi
ereditano da object, cos che qualsiasi caso di ereditariet multipla fornisca pi di un percorso per
arrivare all'oggetto. Per mantenere le classi di base da cui si accede pi di una volta, l'algoritmo dinamico
linearizza l'ordine di ricerca in modo da preservare l'ordinamento da sinistra a destra specificato in ogni
classe, che chiama ciascun genitore solo una volta, e che monotona (cio una classe pu essere
sottoclasse senza influenzare l'ordine di precedenza dei suoi genitori). Nel loro insieme, queste
caratteristiche rendono possibile progettare classi affidabili ed estensibile con ereditariet multipla. Per
una spiegazione pi dettagliata e approfondita, vedere:
http://www.python.org/download/releases/2.3/mro/.
__update=update#copiaprivatadelmetodooriginaleupdate()
classMappingSubclass(Mapping):
defupdate(self,keys,values):
#fornisceunanuovafirmaperupdate()
#manoninterrompe__init__()
foriteminzip(keys,values):
self.items_list.append(item)
Si noti che le regole di ricomposizione sono pensate principalmente per evitare incidenti, ancora
possibile accedere o modificare una variabile considerata privata questo pu anche rivrlarsi utile in
circostanze particolari, come nel debugging.
Notare che il codice passato a exec() o eval() non considera il nome della classe chiamante come
classe corrente, questo effetto simile all'istruzione global, il cui effetto ristretto in modo simile al
codice byte che viene compilato assieme. La stessa limitazione si applica a getattr(), setattr() e
delattr(), cos come quando si fa riferimento direttamente a __dict__.
9.7. Varie.
A volte utile avere un tipo di dati simile al "record" di Pascal o C tipo "struct", associare alcuni elementi
di dati denominati. Una definizione di classe vuota lo far bene:
classImpiegati:
pass
Marco=Impiegati()#Creaunrecordvuotoditipoimpiegati.
#Riempieicampidelrecord.
Marco.Soprannome='Marcol'incredibile'
Marco.Qualifica='Tecnicocomputer'
Marco.Stipendio=1000
Un pezzo di codice Python che prevede un particolare tipo di dato astratto pu essere invece passato a una
classe che emula i metodi di questo tipo di dati. Ad esempio, se si dispone di una funzione che formatta
alcuni dati da un oggetto file, possibile definire una classe con metodi read() e readline() che
ottenga invece i dati da un buffer di stringa, e passarlo come argomento.
L'istanza di metodi di oggetto, possiede anche degli attributi tipo: m.__self__ che l'oggetto istanza
con il metodo m(), e m.__func__ la funzione oggetto corrispondente al metodo.
9.9. Iteratori.
Ormai probabilmente avete notato che la maggior parte degli oggetti possono essere iterati utilizzando
l'istruzione for:
forelementoin[1,2,3]:
print(elemento)
forelementoin(1,2,3):
print(elemento)
forchiavein{'uno':1,'due':2}:
print(chiave)
forstringain"123":
print(stringa)
forlineeinopen("miofile.txt"):
print(linee)
Questo codice, chiaro, conciso e conveniente. L'uso degli iteratori pervade e unifica Python. Dietro le
quinte, l'istruzione for chiama iter() sull'oggetto contenitore. La funzione restituisce un oggetto
iteratore che definisce il metodo__next__() che accede agli elementi nel contenitore uno alla volta.
Quando non ci sono pi elementi, __next__() solleva un'eccezione StopIteration che sancisce la
fine del ciclo for. possibile chiamare il metodo__next__() utilizzando la funzione precostituita
next(), questo esempio mostra come funziona il tutto:
>>>s='abc'
>>>prova=iter(s)
>>>prova
<provaiteratorobjectat0x00A1DB50>
>>>next(prova)
'a'
>>>next(prova)
'b'
>>>next(prova)
'c'
>>>next(prova)
Traceback(mostrecentcalllast):
File"<stdin>",line1,in?
next(prova)
StopIteration
Dopo aver visto i meccanismi alla base del protocollo iteratore, facile aggiungere un comportamento
iteratore alle vostre classi. Definire un metodo __iter__(), che restituisce un oggetto con un metodo
__next__(). Se la classe definisce __next__(), allora __iter__() pu semplicemente restituire
self:
classRovescia:
"""Ciclasuunasequenzarovesciata."""
def__init__(self,data):
self.data=data
self.index=len(data)
def__iter__(self):
returnself
def__next__(self):
ifself.index==0:
raiseStopIteration
self.index=self.index1
returnself.data[self.index]
>>>rovescia=Rovescia('spam')
>>>iter(rovescia)
<__main__.Rovesciaobjectat0x00A1DB50>
>>>forcarattereinrovescia:
...print(carattere)
...
m
a
p
s
9.10. Generatori.
I generatori (Generators) sono uno strumento semplice e potente per la creazione di iteratori. Sono scritti
come funzioni regolari, ma usano l'istruzione yield ogni volta che devono restituire i dati. Ogni volta
che next() viene chiamato su di esso, il generatore riprende da dove si era fermato (si ricorda tutti i
valori dei dati e l'ultima espressione eseguita). Un esempio mostra che i generatori possono essere
banalmente facili da creare:
defrovescia(dati):
forindiceinrange(len(dati)1,1,1):
yielddati[indice]
>>>forcarattereinrovescia('golf'):
...print(carattere)
...
f
l
o
g
Tutto ci che pu essere fatto con i generatori pu essere fatto anche con classi base iteratori come
descritto nella sezione precedente. Ci che rende i generatori cos compatti che i metodi __iter__()
e __next__() , vengono creati automaticamente.
Un'altra caratteristica fondamentale che le variabili locali ed il loro stato di esecuzione vengono salvati
automaticamente tra le chiamate. Questo ha reso la funzione pi facile da scrivere e molto pi chiara che
con un' approccio usando variabili di istanza come self.index e self.data.
Oltre alla creazione automatica del metodo e del salvataggio dello stato del programma, quando i
generatori terminano, sollevano automaticamente StopIteration. In combinazione, queste
caratteristiche rendono facile creare gli iteratori rispetto ad una funzione classica.
>>>xvec=[10,20,30]
>>>yvec=[7,5,3]
>>>sum(x*yforx,yinzip(xvec,yvec))#prodottoscalare
260
>>>frommathimportpi,sin
>>>sine_table={x:sin(x*pi/180)forxinrange(0,91)}
>>>parole_uniche=set(wordforlineinpageforwordin
line.split())
>>>graduatoria=max((student.gpa,student.name)forstudentin
graduates)
>>>data='golf'
>>>list(data[i]foriinrange(len(data)1,1,1))
['f','l','o','g']
[1] Tranne che per una cosa. Oggetti modulo hanno un attributo di sola lettura chiamato __dict__ che
restituisce il dizionario usato per implementare lo spazio dei nomi (namespace) del modulo nascosto,
il nome __dict__ un attributo ma non un nome globale. Ovviamente, questo vola (nel senso di
profanazione e non del colore) l'astrazione dell'implementazione dello spazio dei nomi, e dovrebbe
essere limitato a cose come i debugger post-mortem.
<Restituiscelalistadituttiimodulifunzione>
>>>help(os)
<Restituisceunmanualecompletocreatodalmodulodocstrings>
Per la gestione di file e directory, il modulo shutil fornisce un'interfaccia di pi alto livello pi facile da
usare:
>>>importshutil
>>>shutil.copyfile('miei_dati.db','salvataggio_miei_dati.db')
>>>shutil.move('/build/executables','installdir')
10.6. Matematica.
Il modulo di matematica math d accesso alle funzioni di libreria sottostanti C per la matematica in
virgola mobile:
>>>importmath
>>>math.cos(math.pi/4)
0.70710678118654757
>>>math.log(1024,2)
10.0
Il modulo random , fornisce strumenti per fare delle selezioni casuali:
>>>importrandom
>>>random.choice(['mela','pera','banana'])
'mela'
>>>random.sample(range(100),8)#campionamentosenzasostituzione
[30,83,16,4,8,81,41,50]
>>>random.random()#virgolamobilecasuale
0.17970987693706186
>>>random.randrange(6)#interocasualesu6numeri
4
Il progetto SciPy ha molti altri moduli per calcoli numerici vedere <http://scipy.org>.
>>>fromurllib.requestimporturlopen
>>>forrigainurlopen('http://tycho.usno.navy.mil/cgi
bin/timer.pl'):
...righe=righe.decode('utf8')#Dadatibinariatesto
...if'EST'inrigheor'EDT'inrighe:#cercailTimeZone
...print(righe)
<BR>Nov.25,09:43:32PMEST
>>>importsmtplib
>>>server=smtplib.SMTP('localhost')
>>>server.sendmail('[email protected]','[email protected]',
..."""To:[email protected]
...From:[email protected]
...
...Rispondialpipresto.
...""")
>>>server.quit()
(Notare che nel secondo esempio, necessario che il server di posta attivo sia in localhost.)
>>>importzlib
>>>s=b'Nelmezzodelcamindinostravita......'
>>>len(s)
41
>>>t=zlib.compress(s)
>>>len(t)
37
>>>zlib.decompress(t)
b'Nelmezzodelcamindinostravita......'
>>>zlib.crc32(s)
3044838932
In contrasto con timeit per il buon livello di granuralit, i moduli profile e pstats, forniscono
strumenti per identificare sezioni critiche su grandi blocchi di codice.
>>>print(media([20,30,70]))
40.0
"""
returnsum(valori)/len(valori)
importdoctest
doctest.testmod()#Convalidaautomaticamenteitestintegrati.
Il modulo unittest non pi piacevole del modulo doctest, ma permette una serie pi completa e
capibile di test da essere mantenuto in un file separato:
importunittest
classTestStatisticalFunctions(unittest.TestCase):
deftest_average(self):
self.assertEqual(average([20,30,70]),40.0)
self.assertEqual(round(average([1,5,7]),1),4.3)
withself.assertRaises(ZeroDivisionError):
average([])
withself.assertRaises(TypeError):
average(20,30,70)
unittest.main()#Chiamatodallalineadicomando,chelanciatuttii
test
nei vari paesi in cui vengono utilizzati. L'attributo di raggruppamento della funzione format di locale
fornisce un modo diretto per la formattazione dei numeri con separatori di gruppo:
>>>importlocale
>>>locale.setlocale(locale.LC_ALL,'Inglese_StatiUniti.1252')
'Inglese_StatiUniti.1252'
>>>conv=locale.localeconv()#Acquisisceunamappaconvenzionale
>>>x=1234567.8
>>>locale.format("%d",x,grouping=True)
'1,234,567'
>>>locale.format_string("%s%.*f",(conv['currency_symbol'],
...conv['frac_digits'],x),grouping=True)
'$1,234,567.80'
11.2. Modellazione.
Il modulo string include una classe versatile Template (modello) con una sintassi semplificata
adatta alla modifica da parte di utenti finali. Questo permette di personalizzare le proprie applicazioni
senza dover modificare l'applicazione.
Il formato utilizza dei simboli come segnaposto formate da $ ed altri identificatori validi di Python
(caratteri alfanumerici e di sottolineatura) i quali all'interno di parentesi graffe, permettono la sostituzione
di blocchi di testo in modo dinamico. Scrivendo $ $ crea un unico $ altrimenti non rappresentabile:
>>>fromstringimportTemplate
>>>t=Template('${citt}quartiere110per$causale.')
>>>t.substitute(citt='Roma',causale='accessomusei')
'Romaquartiere110peraccessomusei.'
Il metodo substitute() solleva un KeyError quando un segnaposto non viene fornito in un
dizionario o in un' argomento chiave. Per le applicazioni in stile mail-merge, i dati degli utenti forniti
possono essere incompleti e il metodo safe_substitute() pu essere pi appropriato lasciando cos
il segnaposto invariato se mancano i dati non sollevando errori:
>>>t=Template('Restituisce$oggettoa$proprietario.')
>>>d=dict(item='bicicletta')
>>>t.substitute(d)
Traceback(mostrecentcalllast):
...
KeyError:'proprietario'
>>>t.safe_substitute(d)
'Restituiscebiciclettaa$proprietario.'
Modelli di sottoclassi, possono specificare un delimitatore personalizzato. Ad esempio, un lotto
ridenominato utilit per un visualizzatore di foto pu scegliere di utilizzare segni di percentuale per i
segnaposto come il formato di data corrente, numero di sequenza di immagini, o file:
>>>importtime,os.path
>>>FileFoto=['img_1074.jpg','img_1076.jpg','img_1077.jpg']
>>>classBatchRename(Modello):
...separatore='%'
>>>tmp=input('Stileformato(%ddate%nseqnum%fformat):')
Stileformato(%ddate%nseqnum%fformat):Marco_%n%f
>>>t=BatchRename(tmp)
>>>date=time.strftime('%d%b%y')
>>>fori,NomeFileinenumerate(FileFoto):
...base,ext=os.path.splitext(NomeFile)
...NuovoNome=t.substitute(d=date,n=i,f=ext)
...print('{0}>{1}'.format(NomeFile,NuovoNome))
img_1074.jpg>Marco_0.jpg
img_1076.jpg>Marco_1.jpg
img_1077.jpg>Marco_2.jpg
Un'altra applicazione di modellazione presente nella logica dei dettagli nei programmi in molteplici
formati di output. Ci rende possibile sostituire modelli personalizzati per i file XML, rapporti di testo, e i
rapporti web HTML.
11.4. Multi-threading.
Il Threading una tecnica per il disaccoppiamento dei processi che non sono sequenzialmente dipendenti
e che vengono eseguiti in modo indipendente. I threads (i singoli processi) possono essere utilizzati per
migliorare la reattivit delle applicazioni che accettano input dell'utente mentre altre elaborazioni possono
essere eseguite in background (sottofondo). Un caso d'uso, pu essere quello relativo in funzione di I / O
in parallelo con i calcoli in un altro processo, oppure la scrittura di un file mentre si in attesa di un input
da tastiera.
Il seguente codice, mostra come il modulo di alto livello threading pu essere elaborato in
background mentre il programma principale continua a fare altre cose:
importthreading,zipfile#Importaiduemodulinecessari
classAsincrona(threading.Thread):
def__init__(self,infile,outfile):
threading.Thread.__init__(self)
self.infile=infile
self.outfile=outfile
defrun(self):
f=zipfile.ZipFile(self.outfile,'w',zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finishedbackgroundzipof:',self.infile)
background=Asincrona('mieidata.txt','mioarchivio.zip')
background.start()
print('Ilprogrammaprincipalesempreinprimopiano.')
background.join()#Aspettacheilprocessoinsecondopianotermini
print('Ilprogrammaprincipale,aspettacheilprocessotermini.')
Il principale problema che le applicazioni multi-threaded pongono, sta nella condivisione dei dati con
altre risorse. A tal fine, il modulo threading fornisce una serie di primitive di sincronizzazione, tra cui
blocchi, eventi, variabili di condizione, e semafori.
Con questi potenti strumenti, anche i minimi errori di progettazione, possono causare problemi difficili da
individuare. Quindi, l'approccio preferito per il coordinamento, quello di concentrare tutto l'accesso a
una risorsa in un singolo thread e di utilizzare quindi il modulo queue per alimentare il flusso con
richieste da altri thread. Le applicazioni che utilizzano oggetti queue per la comunicazione inter-thread
per il coordinamento sono pi facili da progettare, pi leggibili e pi affidabili.
11.5. Logging.
Il modulo logging offre un completo sistema di registrazione caratteristico e flessibile. Nel caso pi
semplice, i messaggi di log vengono inviati ad un file o al sys.stderr:
importlogging
logging.debug('Informazionedidebugging')
logging.info('Messaggio')
logging.warning('Attenzione:fileconfig%snontrovato',
'server.conf')
logging.error('Errore!')
logging.critical('Errorecriticouscita')
Che produce il seguente output:
WARNING:root:Attenzione:fileconfigfileserver.confnontrovato
ERROR:root:Errore!
CRITICAL:root:Errorecriticouscita
Per impostazione predefinita, i messaggi informativi e di debug sono soppressi e l'uscita viene inviata su
standard error. Altre opzioni di output includono l'instradamento dei messaggi tramite e-mail, datagrams,
sockets, o ad un server HTTP. Nuovi filtri possono scegliere un' instradamento diverso in base alla priorit
del messaggio: DEBUG, INFO, WARNING, ERROR, e CRITICAL.
Il sistema di registrazione pu essere configurato direttamente da Python o pu essere caricato da un file
di configurazione editabile dall'utente per la registrazione personalizzata senza modificare l'applicazione.
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
d['primario']#statorimossoautomaticamente
File"C:/python33/lib/weakref.py",line46,in__getitem__
o=self.data[key]()
KeyError:'primario'
'python')]
>>>bisect.insort(punti,(300,'ruby'))
>>>punti
[(100,'perl'),(200,'tcl'),(300,'ruby'),(400,'lua'),(500,
'python')]
Il modulo heapq fornisce funzioni per l'attuazione di pile sulla base di liste regolari. La voce pi bassa
del valore sempre mantenuta in posizione zero. Questo utile per applicazioni che accedono
ripetutamente l'elemento di valore pi in basso, ma che non vogliono scorrere l'elenco completo ordinato:
>>>fromheapqimportheapify,heappop,heappush
>>>dati=[1,3,5,7,9,2,4,6,8,0]
>>>heapify(dati)#riarrangialalistanellapila
>>>heappush(dati,5)#aggiungeunnuovovalore
>>>[heappop(dati)foriinrange(3)]#estraeitrepipiccoli
[5,0,1]
Applicazioni finanziarie e altri usi che richiedono una rappresentazione decimale esatta.
Un controllo sulla precisione.
Un controllo sull' arrotondamento per soddisfare i requisiti legali o regolamentari.
Il monitoraggio di importanti cifre decimali.
Applicazioni in cui l'utente si aspetta che i risultati corrispondano ai calcoli fatti a mano.
Ad esempio, calcolare una tassa del 5% su una tariffa telefonica 70 centesimi d risultati diversi in virgola
mobile decimale rispetto al binario in virgola mobile. La differenza diventa significativa se i risultati sono
arrotondati al centesimo pi vicino:
>>>fromdecimalimport*
>>>round(Decimal('0.70')*Decimal('1.05'),2)
Decimal('0.74')
>>>round(.70*1.05,2)
0.73
A causa dei limiti hardware di ogni calcolatore, la precisione restituita dai numeri in virgola mobile
seppur precisa, sempre approssimativa quindi non adatta per certi usi. Decimal invece come gi
accennato sopra, permette di superare questo limite a prezzo di una minore velocit di calcolo. Decimal
permette di definire la precisione in termini di decimali dopo la virgola specificando quanti decimali ci
occorrono con risultati accurati la dove necessitano.
E' possibile inoltre con il modulo decimal definire la precisione dei numeri per tutto il programma o
parte di esso rendendoli come predefiniti.
>>>Decimal('1.00')%Decimal('.10')
Decimal('0.00')
>>>1.00%0.10
0.09999999999999995
>>>sum([Decimal('0.1')]*10)==Decimal('1.0')
True
>>>sum([0.1]*10)==1.0
False
>>>getcontext().prec=36
>>>Decimal(1)/Decimal(7)
Decimal('0.142857142857142857142857142857142857')
12. E Adesso?
La lettura di questa guida probabilmente ha suscitato l'interesse as utilizzare Python per risolvere i
problemi del mondo reale. Cosa si deve fare per saperne di pi?
Questa guida, parte di un gruppo di documentazione Python, altra documentazione possibile trovarla a
questi indirizzi:
The Python Standard Library:
Si consiglia di sfogliare questo manuale, che d un completo (anche se terse) riferimento materiale
sui tipi, funzioni e moduli della libreria standard. La distribuzione standard di Python comprende
un sacco di codice aggiuntivo. Ci sono moduli per leggere caselle di posta Unix, recuperare i
documenti via HTTP, generare numeri casuali, analizzare le opzioni della riga di comando,
scrivere programmi CGI, comprimere i dati, e molti altri compiti. Sfogliando il Reference Library
avrete un'idea di ci che disponibile.
Installing Python Modules spiega come installare moduli esterni scritti da altri utenti Python.
The Python Language Reference: Spiega in modo dettagliato la sintassi e la semantica di Python.
E una lettura un po' pesante, ma utile come una guida completa al linguaggio.
Ancora altre risorse:
http://www.python.org: Il principale sito web di Python. Esso contiene il codice, documentazione
e puntatori a pagine su Python in tutto il web. Questo sito Web si riflette in vari siti del mondo,
come Europa, Giappone e Australia, con una visibilit che pu essere pi veloce rispetto al sito
principale, a seconda della posizione geografica.
http://docs.python.org: L'accesso veloce alla documentazione di Python.
http://pypi.python.org: L'indice dei Packages Python, in precedenza anche soprannominato Cheese
Shop, un indice di moduli Python creati dagli utenti disponibili per il download. Una volta che si
inizia a scrivere del codice utile, puoi registrarti qui e mettere a disposizione degli altri dei moduli
tuoi in modo che possano essere scaricati.
http://aspn.activestate.com/ASPN/Python/Cookbook/: Il Python Cookbook un posto con una
CTRL-P sposta di una riga verso l'alto (indietro) nella memoria storica.
CTRL-N si muove su una riga sotto (se esiste).
CTRL-S avvia una ricerca in avanti.
Ogni linea nella memoria storica, pu essere modificata. Premendo il tasto INVIO si passa la riga
corrente all'interprete.
Il completamento automatico dei nomi delle variabili e dei moduli disponibile come optional. Per
abilitarlo in modalit interattiva dell'interprete, aggiungere quanto segue al file di avvio: [1]
importrlcompleter,readline
readline.parse_and_bind('tab:complete')
La seconda riga, associa il tasto Tab per la funzione di completamento, questo premendo due volte il
tasto Tab.
Un file di impostazioni d'avvio evoluto, potrebbe essere simile a questo esempio. Si noti che questo
cancella i nomi che crea una volta che non sono pi necessari, questo viene fatto in quanto il file di avvio
viene eseguito nello stesso spazio dei nomi dei comandi interattivi, e la rimozione dei nomi evita effetti
collaterali per l'ambiente interattivo. Pu essere utile mantenere alcuni moduli importati, come os, che
risultano essere necessari nella maggior parte delle sessioni dell'interprete.
#Aggiungel'autocompletamentoeunfileperlacronologiacomandi.
#Vieneattivatoautocomplete.
#Settailtasto'Esc'comepredefinito(sipucambiare
#vederealdocumentazionereadline).
#Salvanelfile~/.pystartup,eimpostaunavariabileambiente
#acuipuntare.Che:"exportPYTHONSTARTUP=~/.pystartup"conbash.
importatexit
importos
importreadline
importrlcompleter
historyPath=os.path.expanduser("~/.pyhistory")
defsave_history(historyPath=historyPath):
importreadline
readline.write_history_file(historyPath)
ifos.path.exists(historyPath):
readline.read_history_file(historyPath)
atexit.register(save_history)
delos,atexit,readline,rlcompleter,save_history,historyPath
molto dell'utente, presuppone un' utilizzatore che abbia grande dimestichezza con editor a linea di
comando del tipo vi ed un grande allenamento digitale.
Un'alternativa valida all'interprete interattivo IPython, che dispone del completamento automatico,
l'esplorazione degli oggetti e la gestione avanzata della cronologia. Inoltre esso, pu anche essere
accuratamente adattato e incorporato in altre applicazioni. Un ambiente interattivo avanzato simile
bpython. Un' altro editor molto utilizzato presente su tutte le piattaforme IDLE.
Note:
[1] Python eseguir i contenuti di un file identificato dalla variabile di ambiente PYTHONSTARTUP
quando si avvia l'interprete interattivo. Per personalizzare Python anche per la modalit noninterattiva, fare riferimento a The Customization Modules.
Allo stesso modo, non importa quanti bit su base 2 siete disposti a utilizzare, il valore decimale 0.1 non
pu essere rappresentato esattamente come frazione in base 2. In base 2, 1/10 una frazione che si ripete
all'infinito.
0.0001100110011001100110011001100110011001100110011...
Risulta evidente che sia necessario uno stop all'approssimazione dei decimali in funzione di ci che si
vuole ottenere. Su molte macchine oggi, i numeri in virgola mobile, sono approssimati utilizzando una
frazione binaria con il numeratore che utilizza i primi 53 bit a partire dal bit pi significativo e con il
denominatore come una potenza di due. Nel caso di 1/10, la frazione binaria 3602879701896397 /
2 ** 55 che simile ma non esattamente uguale al valore reale di 1/10.
Molti utenti non sono consapevoli di questa approssimazione a causa del modo in cui vengono visualizzati
i valori. Python stampa solo una approssimazione decimale al valore decimale che l' approssimativo pi
vicino all'hardware della macchina su cui Python viene eseguito. Sulla maggior parte delle macchine, se
Python dovesse stampare il valore decimale vale per il ravvicinamento binario memorizzato per 0.1,
stamperebbe:
>>>0.1
0.1000000000000000055511151231257827021181583404541015625
Che ha cifre pi che sufficienti per la maggior parte degli utilizzatori, quindi Python mantiene il numero
di cifre ad alta approssimazione visualizzando per un valore arrotondato che pi umano.
>>>1/10
0.1
interessante notare che ci sono molti numeri decimali diversi che condividono la stessa vicina frazione
binaria approssimativa.
Ad esempio i numeri:
0.1
0.10000000000000001
0.1000000000000000055511151231257827021181583404541015625
sono tutti approssimati da 3602879701896397 / 2 ** 55. Dal momento che tutti questi valori decimali
condividono la stessa approssimazione, ognuno di loro potrebbe essere visualizzato utilizzando
eval(repr(x)) == x.
Storicamente, la funzione Python precostituita repr() dovrebbe scegliere quella con 17 cifre
significative 0.10000000000000001. Ma a partire da Python 3.1, sulla maggior parte dei sistemi ora in
grado di scegliere la pi breve rappresentazione e visualizzare semplicemente 0.1.
Si noti che questo nella natura stessa del binario in virgola mobile, non un bug in Python, e non un
bug generato dal codice. Vedrete la stessa cosa in tutti i linguaggi che supportano aritmetica in virgola
mobile sul vostro hardware (anche se in alcuni linguaggi potrebbero non visualizzare la differenza per
impostazione predefinita, o in tutte le modalit di uscita).
Per un' output pi piacevole, si potrebbe desiderare di utilizzare i numeri sotto forma di stringhe
formattate per visualizzare solo i decimali voluti.
>>>format(math.pi,'.12g')#Da12decimalisignificativi.
'3.14159265359'
>>>format(math.pi,'.2f')#Da2decimalisignificativi.
'3.14'
>>>repr(math.pi)
'3.141592653589793'
E 'importante rendersi conto che questa solo un' illusione. Si sta semplicemente arrotondando la
visualizzazione del vero valore per la propria macchina. Una illusione pu generarne un' altra. Per
esempio, dal 0.1 non corrisponde esattamente a 1/10, sommando tre valori di 0.1 non si pu produrre
esattamente 0.3, cio:
>>>.1+.1+.1==.3
False
Infatti la vera somma :
0.30000000000000004
Inoltre, dato che il 0.1 non pu ottenere il valore esatto di 1/10 e 0.3 non pu ottenere il valore esatto pi
vicino a 3/10, la funzione round(), ci pu venire in aiuto con un pre-arrotondamento:
>>>round(.1,1)+round(.1,1)+round(.1,1)==round(.3,1)
False
Anche se i numeri non possono essere resi pi vicini ai loro valori esatti previsti, la funzione round()
pu essere utile per il post-arrotondamento in modo che i risultati con i valori esatti diventino
confrontabili tra di loro:
>>>round(.1+.1+.1,10)==round(.3,10)
True
L'aritmetica binaria in virgola mobile riserva molte sorprese come questa. Il problema con "0.1"
spiegato qui sotto in modo pi dettagliato, nella sezione "Errori di rappresentazione". Vedere The Perils of
Floating Point (I pericoli della virgola mobile) per un resoconto pi completo ed altre sorprese.
Come che dice per finire, "non ci sono risposte facili." Comunque, non bisogna drammatizzare ed essere
eccessivamente cauti con i numeri in virgola mobile! Gli errori nelle operazioni che Python fa, vengono
ereditate dall'hardware sottostante, e sulla maggior parte delle macchine sono dell'ordine di non pi di 1
su 2 ** 53 per operazione. Questo pi che sufficiente per la maggior parte delle attivit, anche se va
tenuto conto che ad ogni operazione in virgola mobile pu subire un nuovo errore di arrotondamento,
infatti gli errori si sommano sempre non si sottraggono mai.
Mentre esistono casi patologici, nella maggior parte dell'uso occasionale in virgola mobile avrete il
risultato che vi aspettavate, semplicemente con il numero di cifre decimali che ci si aspetta. La funzione
str() di solito basta, mentre per un controllo pi preciso fare riferimento al metodo str.format()
meglio specificato in Format String Syntax.
Per i casi d'uso che richiedono una rappresentazione decimale pi esatta, provare a utilizzare il modulo
decimal che implementa l'aritmetica decimale adatto per applicazioni di contabilit e applicazioni di
alta precisione.
Un'altra forma di aritmetica esatta supportata dal modulo fractions che implementa aritmetica
basata sui numeri razionali (cos che i numeri 1/3 possono essere rappresentati esattamente).
Se sei un utente che fa uso pesante della virgola mobile, dai un'occhiata al pacchetto Numerical Python
Packagee ed in molti altri pacchetti per le operazioni matematiche e statistiche fornite dal progetto SciPy.
Vedere <http://scipy.org>.
Python fornisce strumenti che possono aiutare in quelle rare occasioni in cui davvero si vuole conoscere il
valore esatto di un numero in virgola mobile. Il metodo float.as_integer_ratio() esprime il
valore in virgola mobile come frazione:
>>>x=3.14159
>>>x.as_integer_ratio()
(3537115888337719,1125899906842624)
Poich il rapporto esatto, pu essere utilizzato per ricreare senza perdite il valore originale:
>>>x==3537115888337719/1125899906842624
True
Il metodo float.hex() rappresenta un valore in virgola mobile in esadecimale (base 16), anche in
questo caso il valore esatto quello memorizzato dal computer:
>>>x.hex()
'0x1.921f9f01b866ep+1'
Questa rappresentazione esadecimale precisa pu essere utilizzata per ricostruire esattamente il valore in
virgola mobile.
>>>x==float.fromhex('0x1.921f9f01b866ep+1')
True
Dal momento che la rappresentazione esatta, questa tecnica utile per scambiare in modo affidabile
valori tra le diverse versioni di Python (indipendenti dalla piattaforma) e lo scambio di dati con altri
linguaggi che supportano lo stesso formato (come Java e C99).
Un altro strumento utile la funzione math.fsum(), che consente di ridurre la perdita di precisione
durante la sommatoria. Essa tiene traccia delle cifre perdute negli arrotondamenti per poi recuperarle nel
finale. Questo pu fare la differenza nella precisione complessiva modo che gli errori non si accumulano
in modo significativo tali da inficiare il risultato finale.
>>>sum([0.1]*10)==1.0
False
>>>math.fsum([0.1]*10)==1.0
True
Errori di rappresentazione si riferisce al fatto che alcune (la maggior parte, in realt), frazioni decimali
non possono essere rappresentate esattamente come nel formato binario (base 2). Questa la ragione
principale per cui Python (o Perl, C, C + +, Java, Fortran, e molti altri), spesso non visualizzano il numero
decimale esatto che ci si aspetta.
Ma perch cos? Perch 1/10 non esattamente rappresentabile come frazione binaria? Quasi tutte le
macchine di oggi utilizzano lo standard IEEE-754 per l'aritmetica in virgola mobile, e quasi tutte le
piattaforme di Python utilizzano IEEE-754 in "doppia precisione". Esso utilizza 53 bit di precisione, per
cui a comando il computer si sforza di convertire 0.1 alla frazione pi vicina che pu della forma J / 2 **
N dove J un intero contenente esattamente 53 bit. Scrivendo
1/10~=J/(2**N)
J~=2**N/10
ricordando che J ha esattamente 53 bit ( > = 2 ** 52 ma < 2 ** 53), il miglior valore per N 56:
>>>2**52<=2**56//10<2**53
True
Cio, il 56 l'unico valore per N che lascia J con esattamente 53 bit. Il valore migliore possibile per J
allora con quoziente arrotondato:
>>>q,r=divmod(2**56,10)
>>>r
6
Poich il resto pi della met di 10, la migliore approssimazione si ottiene arrotondando:
>>>q+1
7205759403792794
Pertanto la migliore approssimazione di 1/10 in 754 doppia precisione :
7205759403792794/2**56