Questo è un corso rapido di minima sul linguaggio di programmazione Python. Per saperne di più, dai un'occhio alla documentazione sul sito web di Python, http://www.python.org/, specialmente il tutorial. Se ti stai chiedendo perchè ti dovrebbe interessare, guarda la pagina dei paragoni, dove Python è paragonato ad altri linguaggi.
Questa introduzione ha ricevuto molte lodi da lettori soddisfatti, ed è stata tradotta in vari linguaggi, fra cui Portoghese, Russo, Norvegese, Coreano e Spagnolo.
(Pagina Python di M. L. Hetland)
1. Fondamenti
Anzitutto, pensa al Python come pseudo-codice.
È quasi vero. Le variabili non hanno tipi, nè si dichiarano.
Appaiono quando le assegni, spariscono quando non le usi più.
L'assegnazione si fa con l'operatore
=
. L'eguaglianza si controlla con l'operatore
==
. Puoi assegnare più variabili alla volta:
x,y,z = 1,2,3 first, second = second, first a = b = 123
I blocchi sono indicati dall'indentazione, e solo
dall'indentazione. (Nè
BEGIN
/END
nè graffe.) Alcune comuni
strutture di controllo:
if x < 5 or (x > 10 and x < 20): print "Il valore è OK." if x < 5 or 10 < x < 20: print "Il valore è OK." for i in [1,2,3,4,5]: print "Iterazione numero", i x = 10 while x >= 0: print "x ancora non negativo." x = x-1
I primi due esempi sono equivalenti.
La variabile indice data nel ciclo for
itera sugli elementi
di una list (scritta come nell'esempio). Per fare un ciclo
for
"normale" (cioè un ciclo di conteggio), usa la
funzione built-in
range()
.
# Stampa i valori da 0 a 99 compresi.
for value in range(100):
print value
(La riga che inizia con "#
" è un
commento, ed è ignorata dall'interprete.)
Ok; ora ne sai abbastanza per (in teoria) implementare qualsiasi
algoritmo in Python. Aggiungiamo un po' di interazione
elementare con l'utente. Per avere input dall'utente (da
un prompt di testo), usa la funzione built-in
input
.
x = input("Immettere un numero: ") print "Il quadrato del numero è", x*x
La funzione input
mostra il prompt passatole (che
può essere vuoto) e permette all'utente di immettere qualsiasi
valore Python valido. In questo caso ci aspettavamo un numero -- se
viene immesso qualcosa d'altro (ad esempio una stringa), il programma
va in crash. Per evitarlo ci servirebbe un po' di controllo degli
errori. Qui non starò a parlarne; basti dire che, se vuoi che
l'input dell'utente sia preso verbatim come stringa (così
che tutto possa venire immesso), userai invece la funzione
raw_input
. Se volessi convertire la stringa immessa
s
in un intero, potresti poi usare int(s)
.
Nota: Se vuoi leggere una stringa con input
,
l'utente dovrà scrivere esplicitamente le virgolette. In Python, le
stringhe possono essere racchiuse fra virgolette semplici o doppie.
Quindi, abbiamo coperto strutture di controllo, input e output -- ora ci servono delle belle strutture dati. Le più importanti sono liste e dizionari. Le liste sono scritte con parentesi quadre, e possono naturalmente essere annidate:
name = ["Cleese", "John"] x = [[1,2,3],[y,z],[[[]]]]
Una delle cose carine delle liste è che puoi accederne gli elementi separatamente o a gruppi, attraverso indiciamento e affettamento. L'indiciamento si fa (come in molti altri linguaggi) appendendo l'indice fra parentesi quadre alla lista. (Nota che il primo elemento ha indice 0).
print name[1], name[0] # Stampa "John Cleese"
name[0] = "Smith"
L'affettamento è quasi come l'indiciamento, eccetto che scriverai
sia l'indice d'inizio sia quello di fine del risultato, con un due-punti
(":
") a separarli:
x = ["spam","spam","spam","spam","spam","eggs","and","spam"]
print x[5:7] # Stampa la lista ["eggs","and"]
Nota che la fine è non-compresa. Se manca uno degli indici, significa
che vuoi tutto in quella direzione. Per esempio
list[:3]
significa "ogni elemento dall'inizio di
list
sino all'elemento 3, non compreso"
(Si potrebbe sostenere che significa in realtà l'elemento
4, poichè il conteggio parte a 0... vabbè).
list[3:]
, d'altra parte, significherebbe
"ogni elemento di list
, partendo dall'elemento 3
(compreso) sino all'ultimo, compreso." Per avere risultati
davvero interessanti, puoi usare anche numeri negativi:
list[-3]
è il terzo elemento dalla fine della
lista...
A proposito di indiciamento, potrebbe interessarti sapere
che la funzione built-in
len
ti dà la lunghezza di una lista.
Ora, dunque -- e i dizionari? Per farla semplice, sono come liste, ma i loro contenuti non sono ordinati. Come si indicizzano allora? Bè, ogni elemento ha una chiave, cioè un "nome" che è usato per trovare l'elemento proprio come in un vero dizionario. Un paio di dizionari d'esempio:
{ "Alice" : 23452532, "Boris" : 252336, "Clarice" : 2352525, "Doris" : 23624643} person = { 'first name': "Robin", 'last name': "Hood", 'occupation': "Scoundrel" }
Ora, per avere l'occupazione di
person
, usiamo l'espressione
person["occupation"]
. Se volessimo cambiare
il suo cognome, potremmo scrivere:
person['last name'] = "of Locksley"
Semplice, no? Come le liste, i dizionari possono contenere altri dizionari. O anche liste. E naturalmente anche le liste possono contenere dizionari. Quindi, si possono facilmente fare strutture dati piuttosto avanzate.
2. Funzione
Prossimo passo: l'astrazione. Vogliamo dare
un nome a un brano di codice, e chiamarlo con un paio di parametri.
In altre parole -- vogliamo definire una funzione (o "procedura").
È facile. Usa la keyword
def
così:
def square(x):
return x*x
print square(2) # Stampa 4
Per quelli di voi che lo capiscono: tutti i parametri in Python sono
passati
per riferimento (come, ad esempio, in Java). Per quelli che
non lo capiscono:
non ve ne preoccupate :)
Python ha gran copia di cose graziose come gli argomenti con nome e gli argomenti di default e può gestire un numero variabile di argomenti a una singola funzione. Per altre informazioni su questo, vedere il tutorial di Python, sezione 4.7.
Se sai usare le funzioni in generale, questo è quel che ti serve
sapere su di loro in Python. (Ah sì... la keyword
return
termina l'esecuzione della funzione e restituisce
il valore datole.)
Una cosa che potrebbe esserti utile sapere, però, è che in
Python le funzioni sono
valori. Così, se hai una funzione come square
,
potresti fare qualcosa come:
queeble = square queeble(2) Stampa 4
Per chiamare una funzione senza argomenti devi ricordarti di scrivere
doit()
e non doit
. Quest'ultimo, come abbiamo
mostrato, ritorna solo la funzione stessa, come valore. (Questo vale
anche per i metodi degli oggetti... vedi oltre.)
3. Oggetti e roba...
Penso tu sappia come funziona la
programmazione a oggetti. (Altrimenti, questa sezione potrebbe non
avere molto senso per te. Non importa... comincia a giocare senza
gli
oggetti :)
.) In Python si definiscono le classi con la
keyword (sorpresa!)
class
, così:
class Basket:
# Ricorda sempre l'argomento *self*
def __init__(self,contents=None):
self.contents = contents or []
def add(self,element):
self.contents.append(element)
def print_me(self):
result = ""
for element in self.contents:
result = result + " " + `element`
print "Contiene:"+result
Cose nuove qui:
self
in questo esempio, il che è l'abitudine.)
object.method(arg1,arg2)
.
__init__
, sono
predefiniti, con significati speciali.
__init__
è il nome del costruttore
della classe, cioè la funzione chiamata quando crei un'istanza.
def spam(age=32): ...Qui,
spam
può essere chiamata con
uno o zero parametri. Se non ne vengono usati, il parametro
age
avrà valore 32.
element
contiene il numero 1, allora `element`
è
lo stesso di
"1"
mentre 'element'
è una stringa letterale.)
+
è usato anche per concatenare
liste e stringhe. Le stringhe in realtà sono solo liste di caratteri
(il che significa che potete usare su di esse indiciamento e affettamento
e la funzione len
. Ganzo, eh?)
Nessun metodo (nè variabile membro) è protetto (o privato o simile)
in Python. L'incapsulamento è praticamente questione di stile di
programmazione. (Se ti serve davvero, ci sono convenzioni sui
nomi che permettono un po' di
privacy :)
).
Ora, quella logica corto-circuito...
Tutti i valori in Python possono essere usati come valori logici.
Alcuni dei più "vuoti", come
[]
, 0
, ""
e
None
rappresentano la falsità logica, mentre la maggior
parte degli altri valori (come
[0]
, 1
o "Hello, world"
) rappresentano
la verità logica.
Ora, le espressioni logiche come
a and b
sono valutate così:
Primo, si controlla se
a
è vero. Se non lo è, è il risultato. Se lo
è, il risultato è b
(che rappresenterà il
valore di verità dell'espressione.) La logica corrispondente per
a or b
è: se a
è vero, è il risultato.
Se non lo è, il risultato è b
.
Questo meccanismo fa sì che and
e or
si
comportino come gli operatori booleani che dovrebbero implementare,
ma ti permette anche di scrivere espressioni condizionali semplici
e dolci. Per esempio, l'istruzione
if a: print a else: print b
potrebbe essere scritta anche:
print a or b
In effetti, questo è piuttosto idiomatico in Pyton, quindi meglio
abituarcisi. È quel che facciamo nel metodo
Basket.__init__
. L'argomento
contents
ha un valore di default di None
(che è,
fra le altre cose, false). Quindi, per controllare se ha un valore,
potremmo scrivere:
if contents: self.contents = contents else: self.contents = []
Naturalmente, ora sai che c'è un modo migliore. E perchè non gli
diamo il valore di default di
[]
da subito? Perchè a causa di come funziona Python,
questo darebbe a tutti i Basket la stessa lista vuota
come contenuto di default. Appena uno comincia a riempirsi, tutti
conterrebbero gli stessi elementi, e il default non sarebbe più
vuoto... per imparare di più su questo, dovresti leggere la
documentazione e cercare la differenza fra
identità e eguaglianza.
Un altro modo di fare quanto sopra è:
def __init__(self, contents=[]): self.contents = contents[:]
Puoi indovinare come questo funziona? Invece di usare la stessa
lista vuota dappertutto, usiamo l'espressione
contents[:]
per fare una copia. (Semplicemente,
affettiamo il tutto.)
Così, per fare effettivamente un
Basket
e usarlo (cioè chiamare qualche metodo su
di esso) faremo qualcosa come:
b = Basket(['apple','orange']) b.add("lemon") b.print_me()
Ci sono altri metodi magici oltre a __init__
. Uno di essi è
__str__
, che definisce che aspetto vuole avere l'oggetto se viene
trattato come stringa. Potremmo usarlo nel nostro Basket invece di
print_me
:
def __str__(self): result = "" for element in self.contents: result = result + " " + `element` return "Contains:"+result
Ora, se volessimo stampare il Basket
b
, potremmo semplicemente usare:
print b
Ganzo, eh?
Le sottoclassi si fanno così:
class SpamBasket(Basket):
# ...
Python permette eredità multipla, quindi puoi avere varie
superclassi fra parentesi, separate da virgole. Le classi si istanziano così:
x = Basket()
. I costruttori, come dicevo, si fanno definendo la
speciale funzione membro
__init__
. Supponiamo che
SpamBasket
abbia un costruttore__init__(self,type)
.
Allora potresti farne uno così: y = SpamBasket("apples")
.
Se, nel costruttore di
SpamBasket
, ti servisse chiamare il costruttore di una
o più superclassi, potresti chiamarlo così:
Basket.__init__(self)
. Nota che, oltre ai normali
parametri, devi fornire esplicitamente
self
, poichè la
__init__
della superclasse non sa con quale istanza
stia trattando.
Per altre meraviglie sulla programmazione a oggetti in Python, vedi la sezione 9 del tutorial.
4. Un trucco mentale Jedi.
(Questa sezione è qua solo perchè
penso che sia bella. Decisamente
non è necessario leggerla per iniziare a imparare
Python.)
Ti piacciono i concetti sbalorditivi? Allora, se sei davvero audace, potresti dare un'occhiata al saggio di Guido van Rossum sulle metaclassi. Se però preferisci che il tuo cervello non esploda, potrebbe bastarti questo trucchetto.
Python usa spazi di nomi dinamici e non lessicali. Questo significa che se hai una funzione così:
def orange_juice(): return x*2
... dove una variabile (in questo caso x
) non è connessa
a un argomento e non riceve un valore entro la funzione, Python userà
il valore che essa ha dove e quando la funzione è chiamata. In questo caso:
x = 3 y = orange_juice() # y è ora 6 x = 1 y = orange_juice() # y è ora 2
Di solito, questo è il tipo di comportamento che desideri (benchè questo esempio sia un po' artificioso - raramente si accede così alle variabili.) Tuttavia, a volte può essere carino avere qualcosa di simile a uno spazio di nomi statico, cioè, memorizzare alcuni valori dall'ambiente nella funzione quando viene creata. Il modo di fare questo in Python è attraverso gli argomenti di default.
x = 4 def apple_juice(x=x): return x*2
Qui, l'argomento
x
riceve un valore di default che è eguale al
valore della variabile x
nel momento in cui la
funzione viene definita. Quindi, sinchè nessuno fornisce un
argomento per la funzione, si comporterà così:
x = 3 y = apple_juice() # y is now 8 x = 1 y = apple_juice() # y is now 8
Così - il valore di x
non è cambiato. Se ci servisse
solo questo, avremmo equivalentemente potuto scrivere:
def tomato_juice(): x = 4 return x*2
o anche
def carrot_juice(): return 8
Tuttavia, il punto è che il valore di x
è
raccolto dall'ambiente nel momento in cui la funzione viene
definita. In che modo questo è utile? Facciamo un esempio -- una
funzione che compone altre due funzioni.
Vogliamo una funzione che lavora così:
from math import sin, cos sincos = compose(sin,cos) x = sincos(3)
Dove compose
è la funzione che vogliamo costruire, e
x
ha il valore -0.836021861538
, cioè
sin(cos(3))
. Ora, come facciamo questo?
(Nota che qui stiamo usando funzioni come argomento... il che è un trucco già parecchio carino in sè.)
Chiaramente,
compose
accetta due funzioni come parametri, e
restituisce una funzione che accetta un parametro. Quindi,
uno scheletro di soluzione potrebbe essere:
def compose(fun1, fun2):
def inner(x):
pass # ...
return inner
Potremmo essere tentati di scrivere
return fun1(fun2(x))
entro la funzione
inner
e accontentarci. No, no, no. Questo si comporterebbe
molto stranamente. Immagina il seguente scenario:
from math import sin, cos
def fun1(x):
return x + " world!"
def fun2(x):
return "Hello,"
sincos = compose(sin,cos) # usa la versione sbagliata
x = sincos(3)
Ora, che valore avrebbe x
? Esatto: "Hello,
world"
. Perchè? Perchè quando compose
viene chiamata, raccoglie i
valori di
fun1
e fun2
dall'ambiente, non quelli che
erano in giro quando fu creata. Per avere una soluzione funzionante,
tutto quel che dobbiamo fare è usare la tecnica che ho descritto
prima:
def compose(fun1, fun2): def inner(x, fun1=fun1, fun2=fun2): return fun1(fun2(x)) return inner
Ora dobbiamo solo sperare che nessuno passi alla funzione
risultante più di un argomento, perchè questo la romperebbe
:)
. A proposito, visto che non ci serve
il nome inner
, ed esso contiene solo un'espressione,
tanto vale fare una funzione anonima, usando la
keyword lambda
:
def compose(f1, f2): return lambda x, f1=f1, f2=f2: f1(f2(x))
Conciso, ma chiaro. Devi amarlo :)
(E se non ne hai capito nulla, non preoccuparti. Almeno spero
ti abbia convinto che Python è più che "solo un linguaggio
di scripting"...
:)
)
5. E ora...
Giusto poche cosette vicino alla fine.
La maggioranza delle funzioni e classi utili sono piazzate in
moduli, che sono file di testo contenenti codice
Python. Puoi importarli e usarli nei tuoi programmi. Per esempio,
per usare il metodo split
del modulo standard
string
, puoi fare, o:
import string x = string.split(y)
Oppure...
from string import split x = split(y)
Per altre informazioni sui moduli della libreria standard, dai un'occhiata a www.python.org/doc/lib. Contengono un mucchio di roba utile.
Tutto il codice nel modulo/script è eseguito quando viene importato. Se vuoi che il tuo programma possa essere usato sia come modulo importabile sia come programma eseguibile, aggiungi alla fine di esso qualcosa come:
if __name__ == "__main__": go()
Questo è un modo magico per dire che se questo modulo viene
fatto girare come script eseguibile (cioè, se non stiamo venendo
importati da un altri script), allora va chiamata la funzione
go
. Naturalmente, potresti fare
qualsiasi cosa in questa posizione dopo il
due-punti... :)
E per quelli di voi che vogliono rendere eseguibile uno script su UN*X, usate la seguente prima riga per farlo funzionare da solo:
#!/usr/bin/env python
Infine, breve menzione di un concetto importante: le Eccezioni. Alcune operazioni (come dividere per zero, o leggere da un file inesistente) producono una condizione di errore, cioè di eccezione. Puoi anche farti le tue, sollevandole in momenti appropriati.
Se non viene gestita l'eccezione, il tuo programma termina e
stampa un messaggio di errore. Puoi evitarlo con una
istruzione di
try
/except
. Per esempio:
def safe_division(a,b): try: return a/b except ZeroDivisionError: return None
ZeroDivisionError
è un'eccezione standard. In questo
caso,
avresti potuto controllare se b
era zero,
ma in molti casi, questa strategia non è applicabile. Inoltre,
se non avessimo la clausola
try
in safe_division
, cioè se fosse
una funzione rischiosa da chiamare, potremmo ancora fare
qualcosa come:
try: unsafe_division(a,b) except ZeroDivisionError: print "Something was divided by zero in unsafe_division"
Nei casi in cui normalmente non ci sarebbe uno specifico problema, però potrebbe succedere, usare le eccezioni permette di evitare costosi controlli ecc.
Beh, questo è tutto. Spero tu abbia imparato qualcosa. Ora
vai e gioca. E ricorda il motto
per imparare il Python:
"Use the source, Luke." (Traduzione: leggi tutto il codice su cui
puoi mettere le mani :)
) Per cominciare, ecco un esempio. È
il ben noto algoritmo
QuickSort di Hoare. Una versione con sintassi colorizzata è qui.
C'è una cosa che può meritare di essere detta su questo esempio.
La variabile
done
controlla se la
partition
abbia o meno finito di muovere gli elementi.
Quindi, quando uno dei due cicli interni vuol terminare l'intera
sequenza di scambi, mette
done
ad 1
, poi esce con
break
. Perchè i cicli interni usano
done
? Perchè, quando il primo ciclo interno finisce con
break
, se il prossimo ciclo debba partire o meno dipende
dal fatto che il ciclo principale sia finito, cioè, se
done
sia stata o meno posta ad
1
:
while not done: while not done: # Itera sino ad un break while not done: # Eseguito solo se il primo non ha posto "done" ad 1
Una versione equivalente, forse più chiara, ma nella mia opinione meno bellina, sarebbe:
while not done: while 1: # Itera sino ad un break if not done: while 1: # Eseguito solo se il primo non ha posto "done" ad 1
L'unica ragione per cui ho usato la variabile done
nel primo
ciclo era che mi piaceva conservare la simmetria fra i due. Così li si
potrebbe scambiare e l'algoritmo funzionerebbe ancora.
Alcuni altri esempi si trovano sulla pagina dei bocconcini di Joe Strout.