Python/Sequenze
Tra i dati messi a disposizione da Python, alcuni hanno delle caratteristiche in comune: sono le sequenze.
Le sequenze sono dei contenitori di oggetti che mantengono l'ordine. Sono sequenze le liste, le tuple e le stringhe.
Liste
modificaUna lista è un contenitore ordinato di oggetti Python. Può essere costruita usando le parentesi quadre:
lista0=['a', 34, ['s', 47]] # ['a', 34, ['s', 47]]
o il costruttore list:
lista1=list("delta") # ['d', 'e', 'l', 't', 'a']
A volte può essere utile costruire una lista vuota da riempire in seguito:
lista2=[]
oppure
lista3=list()
La funzione range(<n>) restituisce una lista formata dai primi <n> numeri naturali:
lista4=range(10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Si può osservare qui che Python restituisce una lista formata effettivamente da 10 elementi da zero compreso a dieci escluso.
Python mette a disposizione un comodo metodo per costruire liste, la 'list comprehension'. Se ad esempio voglio una lista con i quadrati dei primi 10 numeri naturali posso scrivere:
lista6=[n*n for n in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Nella costruzione di liste si può aggiungere anche una condizione. Se ad es. volessi i quadrati dei soli numeri pari:
lista7=[n*n for n in range(10) if n % 2 == 0] # [0, 4, 16, 36, 64]
Le liste sono oggetti modificabili, quindi è possibile inserire, cancellare o cambiare gli oggetti contenuti in una lista:
lista=['Nel', 0.5, 'del', 'cammin', 'nostra', 'pippo', 'vita']
print lista # ['Nel', 0.5, 'del', 'cammin', 'nostra', 'pippo', 'vita']
lista[1]='mezzo'
print lista # ['Nel', 'mezzo', 'del', 'cammin', 'nostra', 'pippo', 'vita']
del(lista[5])
print lista # ['Nel', 'mezzo', 'del', 'cammin', 'nostra', 'vita']
lista.insert(4, 'di')
print lista # ['Nel', 'mezzo', 'del', 'cammin', 'di', 'nostra', 'vita']
Il metodo più utilizzato per popolare liste, dopo la list comprehension è l'uso del metodo append:
lista=[]
for i in range(3):
lista .append(raw_input("Stringa n° %s: " % i))
print lista
['pippo', 'pluto', 'paperoga']
Tutti i metodi delle liste si possono ottenere con l'istruzione:
>>> help(list)
Tuple
modificaLe tuple sono contenitori ordinati di oggetti Python. A differenza delle lista non sono modificabili, quindi una volta costruita una tupla non si può cancellare, cambiare o inserire un elemento. Può essere costruita usando le parentesi tonde:
tupla0=('a', 34, ['s', 47]) # ('a', 34, ['s', 47])
o il costruttore tuple:
tupla1=tuple("delta") # ('d', 'e', 'l', 't', 'a')
Una tupla vuota risulta piuttosto inutile dato che, essendo immutabile, non può essere popolata.
La scelta di usare lo stesso simbolo per le parentesi delle espressioni e per indicare le tuple, ha portato ad un problema di ambiguità. Con l'espressione:
a=(6) # 6
potremmo voler associare ad a il risultato dell'espressione (6) o la tupla che contiene il solo elemento 6. GVR ha dato la precedenza all'espressione. Per realizzare una tupla formata da un solo elemento dobbiamo aggiungere una virgola:
a=(6,) # (6,)
Tutti i metodi delle tuple si possono ottenere con l'istruzione:
>>> help(tuple)
Stringhe
modificaLe stringhe sono sequenze di caratteri. Anche le stringhe non sono modificabili, quindi una volta costruita una stringa non la si può modificare. Può essere costruita usando gli apici, singoli o doppi in diversi modi:
stringa0="foo"
stringa1='bar'
stringa2="""altro modo"""
stringa3='''e infine'''
Le ultime due stringhe possono essere scritte anche su più righe. La funzione str permette di convertire altri oggetti in stringhe:
stringa4=str(45.3) # '45.3'
Altro modo per costruire stringhe componendo diversi elementi:
stringa5="sqrt(%s^2+%s^2)=%s" % (3, 4, 5) # 'sqrt(3^2+4^2)=5'
I simboli %s, presenti nella stringa, sono dei segnaposto che vengono sostituiti, ordinatamente, dagli elementi presenti nella tupla che segue l'operatore %.
Tutti i metodi delle stringhe si possono ottenere con l'istruzione:
>>> help(str)
Scorrere le sequenze
modificaÈ possibile scorrere tutti gli elementi di una sequenza usando un iteratore. Python mette a disposizione molti iteratori, ma il più usato è: for.
La sintassi è:
for <variabile> in <sequenza>: <istruzioni>
un semplice esempio di uso dell'iteratore for è:
def stampa_in_verticale(sequenza):
"""Visualizza gli elementi di una sequenza, uno sotto l'altro."""
for elemento in sequenza:
print elemento
def test():
lista=['Et', 'telefono', 'casa']
stampa_in_verticale(lista)
print
tupla=('M.Beri', 'Python', 'Apogeo', 2007, 7.50)
stampa_in_verticale(tupla)
print
stringa="scala"
stampa_in_verticale(stringa)
print
test()
Anche i file di testo e altri oggetti Python si possono scorrere come le sequenze. Ad esempio se abbiamo un file di testo "commedia.txt" le istruzioni:
testo=file("commedia.txt")
stampa_in_verticale(testo)
print
insieme alla funzione scritta sopra, permetteranno di stampare il suo contenuto una riga sotto l'altra.
Accedere ai singoli elementi
modificaSi può accedere ai singoli elementi di una sequenza indicandone la posizione tra parentesi quadre. Si deve tenere presente che in Python ogni sequenza inizia dalla posizione zero quindi il primo elemento ha indice 0 il secondo 1 e così via:
stringa="Tre civette sul comò"
print stringa[0] # 'T'
print stringa[1] # 'r'
print stringa[3] # ' '
Il meccanismo dell'indicizzazione può essere usato con tutte le sequenze quindi funziona allo stesso modo anche con liste e tuple:
lista=[26, "pippo", [13, 12, 2008], (6, 35)]
print lista[0] # 26
print lista[1] # 'pippo'
print lista[2][1] # 12
L'ultima istruzione stampa l'elemento di posto 1 dell'elemento di posto 2 di lista. L'ultima istruzione indica il meccanismo per trattare matrici a enne dimensioni. Nel caso di una matrice a due dimensioni possiamo scrivere una funzione che ne visualizzi gli elementi:
def stampa_matrice(m):
"""Visualizza gli elementi di una matrice."""
for riga in m:
for e in riga:
print e, "\t",
print
def test():
matrice=[[34, 64, 83],[38, 17, 25],[12, 18, 69]]
stampa_matrice(matrice)
La stringa "\t" indica un tabulatore.
È anche possibile usare come indici numeri negativi, in questo caso -1 indica l'ultimo elemento, -2 il penultimo e così via:
lista=[26, "pippo", [13, 12, 2008], (6, 35)]
print lista[-1] # (6, 35)
print lista[-2][0] # 13
Affettare sequenze (slicing)
modificaData una sequenza è possibile ricavarne un'altra che contenga parte dei suoi elementi. La sintassi assomiglia a quella dell'indicizzazione, si usano sempre parentesi quadrate, ma questa volta devono essere presenti due indici che individuano la fetta da copiare. I due indici devono essere separati dal simbolo ":". Nei prossimi esempi mi riferisco a una stringa ma funzionano allo stesso modo con qualunque sequenza, quindi anche con liste o tuple.
stringa="Tre civette sul comò"
s=stringa[4:11]
print s # civette
Coerentemente con il resto del linguaggio il primo indice è compreso nel risultato il secondo è escluso quindi l'istruzione precedente estrae la sottostringa dal carattere di posto 4 compreso al carattere di posto 11 escluso, 11 - 4 = 7 caratteri. Se devo estrarre i primi elementi di una sequenza posso sottintendere il primo indice:
s=stringa[:3]
print s # Tre
Allo stesso modo per estrarre gli ultimi elementi di una sequenza posso omettere il secondo indice:
s=stringa[16:]
print s # comò
Nell'ultimo caso sarebbe stato più comodo usare un indice negativo:
s=stringa[-4:]
print s # comò
La sintassi dell'affettamento può accettare un terzo argomento che indica un intervallo, così se voglio estrarre solo le lettere di posto pari della parola 'civette':
s=stringa[4:11:2]
print s # cvte
A volte è utile avere una copia di una lista che è un oggettio mutabile, la si può ottenere con l'istruzione:
lista=['uno', 'due', 'tre']
copia=lista[:]
print copia # ['uno', 'due', 'tre']
Non c'è bisogno di costruire copie di un oggetto immutabile, ma perché con le liste questo può servire? Consideriamo la seguente porzione di codice:
lista0=['uno', 'due', 'tre']
lista1=lista0
print lista0 # ['uno', 'due', 'tre']
print lista1 # ['uno', 'due', 'tre']
Sembrerebbe che il programma abbia realizzato la copia di lista0 e l'abbia assegnata alla variabile lista1. Ma le cose non sono così: il programma ha creato un nuovo identificatore che si riferisce sempre allo stesso oggetto lista. Ora se modifico un elemento della lista: e stampo di nuovo gli oggetti collegati a lista0 e lista1 ottengo:
lista0=lista0[1]='cinque'
print lista0 # ['uno', 'cinque', 'tre']
print lista1 # ['uno', 'cinque', 'tre']
Questo avviene perché ho modificato l'oggetto lista che è collegato sia a lista0 sia a lista1. Il seguente programma crea invece un nuovo oggetto lista che collega all'identificatore lista1:
lista0=['uno', 'due', 'tre']
lista1=lista0[:]
print lista0 # ['uno', 'due', 'tre']
print lista1 # ['uno', 'due', 'tre']
lista0=lista0[1]='cinque'
print lista0 # ['uno', 'cinque', 'tre']
print lista1 # ['uno', 'due', 'tre']
Il programma precedente ha costruito una sola lista collegata a due identificatori diversi, il secondo, dopo aver costruito una lista collegata all'identificatore lista0, ne costruisce un'altra, con gli stessi elementi e la collega all'identificatore lista1. In questo modo le modifiche effettuate sull'oggetto collegato all'identificatore lista0 non hanno effetto sull'oggetto collegato a lista1.