Abbiamo visto come con python possiamo definire semplicemente dei numeri (interi, decimali, complessi), delle liste di elementi (che possiamo usare per rappresentare dei vettori) e delle funzioni.
Ci restano da vedere molto velocemente:
Le vediamo brevemente direttamente nel workspace.
Le liste sono sequenze di elementi che non possono essere modificati. Ogni elemento di una tupla può essere di qualsiasi tipo, e gli elementi possono essere tutti di tipi diversi tra loro. Diversamente dalle liste, da una tupla non si possono rimuovere o aggiungere elementi: è un oggetto di tipo read only (come Complex). A differenza delle liste, le tuple sono rappresentate come una sequenza di oggetti racchiusi tra parentesi tonde (per le liste si usa le quadre).
In [ ]:
x=2,4
print(type(x))
In [ ]:
print(x, x[0], x[1])
In [ ]:
x[1] = 4
In [ ]:
a,b = 2,4
In [ ]:
a,b = b,a
In [ ]:
print(a,b)
In [ ]:
t1 = (2, 'ciao', 5)
t2 = (3.14, 987)
# Concatenazione
print('concatenazione:', t1+t2)
# Indicizzazione
print('indicizzazione:',t1[1])
# Slicing
print('slicing:',(t1+t2)[2:])
# Repetition
print('repetition:',t2*3)
NOTA: Per definire una tuple di lunghezza pari a uno, ovvero di un singolo elemento, bisogna usare la strana sintassi (1,)
: si noti la virgola dopo l'uno.
In [ ]:
a=(1)
b=(1,)
print(type(a), type(b))
ESERCIZIO 1: Scrivere una funzione che prende in input due tuple e restituisce una tupla che contiene gli elementi che sono sia nella prima che nella seconda tupla. Scrivere anche una funzione di test che comprenda qualche caso significativo.
In [ ]:
def Intersect(As, Bs):
# COMPLETARE
# COMPLETARE
return As
def UnitTest():
# COMPLETARE
# COMPLETARE
pass
ESERCIZIO 2: (obiettivo: intuire il vantaggio di poter avere anche oggi non mutabili)
Si scriva una funzione che prenda in input due liste e che rimuove dalla prima lista ogni elemento che compare nella seconda lista. La funzione non ritorna nulla, ma modifica la prima lista data in input.
Si può usare il metodo L.remove(e)
che rimuove dalla lista L
il primo elemento uguale a e
. Per testare se un elemento appartiene ad una lista basta eseguire il controllo e in L
:
if 3 in [1,2,3,4,5]:
print('ok')
else:
print('failed')
In [ ]:
def RimuoviDuplicati(As, Bs):
# DA COMPLETARE
# DA COMPLETARE
pass
L1 = [2, 4, 2, 5, 6, 6, 3, 2, 9, 4]
L2 = [2, 4, 7]
RimuoviDuplicati(L1, L2)
print('L1 =', L1)
In [ ]:
Techs = ['MIT', 'Caltech']
Ivys = ['Harvard','Yale','Penn']
U1 = [Techs, Ivys]
U2 = [['MIT', 'Caltech'], ['Harvard','Yale','Penn']]
print(U1 == U2)
print(id(U1) == id(U2)) # la funzione id() restituisce l'identificativo unico di un oggetto python
In [ ]:
Techs.append('Standford')
print(U1 == U2)
In [ ]:
U1[0].remove('Standford')
print(Techs)
NOTA: abbiamo due percorsi diversi che portano allo stesso oggetto di tipo lista: il primo attraverso il nome della lista Techs
, il secondo attraverso il primo elemento della lista U1
. Basta modificare uno dei due, che il cambiamento si riflette sull'altro: si parla in questo caso di side effect, in quanto si potrebbero introdurre degli effetti non desiderati, difficili da individuare. Notare che problemi di questo tipo non si hanno con strutture dati di tipo read only.
In [ ]:
commento = "Enrico, stai sereno!"
for c in commento:
print(c.upper(), end=' ')
Per vedere alcuni metodi utili sulle funzioni, ricordarsi di usare il tab destro per l'autocompletion dopo il nome+punto di una variabile:
commento. '+' <tab>
Esempio:
In [ ]:
#commento.
In [ ]:
# INDICIZZAZIONE E SLICING
print(commento[3], commento[-1], commento[2:5])
In [ ]:
print(commento.lower())
In [ ]:
print(commento.upper())
Da notare che la funzione upper
non ha modifcato la stringa commento
, ma ha restituito una nuova lista con tutte le lettere maiuscole. La maggior parte delle funzioni standard di python che opera sulle stringhe operano in questo modo. Per maggiori dettagli, potete sempre consultare help(str)
.
In [ ]:
commento
I seguenti metodi sono tutti molto utili e restituiscono delle nuove stringhe lasciando la stringa iniziale immutata:
s.count(s1)
: conta qualche volte la stringa s1
è contenuta in s
s.find(s1)
: restituisce l'indice della stringa s
in cui ha trovato per la prima volta la stringa s1
; altrimenti restituisce -1s.rfind(s1)
: come sopra, ma inizia dalla fine di s
(la r
sta per reversed
)s.replace(old,new)
: sostituisce tutte le sottostringhe uguali a old
in s
con la stringa new
s.strip()
: rimuove tutti i caratteri blanks dalla stringa s
s.split(d)
: suddivide la stringa in sottostringhe usando il carattere d
come separatoreI dizionari sono una struttura dati molto utilizzati in python. Sono delle strutture dati che corrispondono a delle liste di coppie (key, value). I dizionari sono degli oggetti mutabili come le liste, ma non sono una sequenza ordinata, e quindi non possono essere indicizzati con dei numeri interi.
La key viene utilizzata come chiave per indicizzare un value. Per esempio:
Dict["hello"] = "ciao"
Abbiamo la chiave "hello" utilizzata per indicizzare l'elemento "ciao" nel dizionario Dict. Per semplicita', potete pensare ai dizionari a come dei vettori di elementi indicizzati da altri oggetti immutabili, come ad esempio delle stringhe.
ESEMPIO:
In [ ]:
# Creo un dizionario vuoto
Vocabolario = dict()
print(type(Vocabolario))
In [ ]:
Vocabolario["keep"] = "stai"
Vocabolario["calm"] = "sereno"
print("Enrico,", Vocabolario["keep"], Vocabolario["calm"])
In [ ]:
# E` possibile enumerare i dizionari con un ciclo for
Vocabolario["hello"] = "ciao"
for key in Vocabolario:
print("chiave:", key, "- valore:", Vocabolario[key])
I seguenti metodi sono molto utili per usare i dizionari:
len(d)
: restituisce il numero di elementi nel dizionario d
d.keys()
: restituisce una vista delle chiavi del dizionario d
d.values()
: restituisce una vista dei valori del dizionario d
key in d
: restituisce True
se la chiave key
è nel dizionario d
d.get(key, value)
: restituisce d[key]
se key
è in d
, altrimenti restituisce il valore value
d[key] = value
: associa il valore value
alla chiave key
nel dizionario d
del d[key]
: rimuove la chiave k
dal dizionario d
for key in d
: itera sulle chiavi del dizionario d
È possibile definire degli insiemi di elementi usando oggetti di tipo set
: questi sono delle collezioni non ordinate di oggetti mutabili (più precisamente su cui è definita una funzione di hash
). Sono molto utili quando si deve controllare l'appartenenza di un elemento ad un dato insieme, avere delle collezioni di oggetti senza duplicati, oppure se si devono effetturare delle operazioni su insiemi come unione, intersezione e differenza tra insiemi.
Per maggiori dettagli, si rimanda alla documentazione ufficiale.
ESEMPIO:
In [ ]:
A = set([2,3,4,2,4,6,7,8])
print(A)
print(3 in A)
B = set([4,4,2,1])
A = A.intersection(B)
print(A)
A = A.difference(B)
print(A)
In [ ]:
class MyComplex:
def __init__(self, Real, Img):
self.real = Real
self.img = Img
def __str__(self):
s = str(self.real)
if self.img >= 0:
s += '+'
s += str(self.img)+'j'
return s
def coniugate(self):
return MyComplex(self.real, -self.img)
In [ ]:
c = MyComplex(1,4)
In [ ]:
print(c)
In [ ]:
print(c.coniugate())
In [ ]:
c.img
In [ ]:
type(c)
In [ ]:
c.img = 5
print(c.coniugate())
Per leggere un file di testo chiamato filename
, bisogna prima "aprirlo" con il comando open(filename, mode)
usando la modalità mode='r'
. Si usi invece mode='w'
se si vuole scrivere un nuovo file oppure mode='a'
se vuole aggiungere righe in coda ad un file esistente. Il metodo open
restituisce un file handle (una sorta di puntatore) per poter accedere al file e manipolarne il contenuto.
ESEMPIO: Il seguente codice, apre il file di testo train-small.csv
(il suffisso ".csv" sta per "comma separated values") e ne legge una riga alla volta stampandola a video. Il file contiene le informazioni di 10 passeggeri del Titanic.
In [ ]:
doc = open('data/train-small.csv', 'r')
for row in doc:
print(row)
doc.close()
Si noti che in effetti ogni riga del file contiene una serie di valori separati da una virgola e che è come se ogni riga contennesse già il carattere \n
che stampa delle righe vuote.
I seguenti metodi sono molto utili per manipolare dei files:
open(filename, mode)
: apre il file chiamato "filename" in modalità mode
(lettura, scrittura, aggiunta)pf.read()
: restituisce un'unica stringa contenente l'intero contenuto del filepf.readline()
: restituisce la prossima riga associata al file handler pf
pf.readlines()
: restituisce una lista di stringhe, una per ciascuna riga contenuta nel filepf.write(s)
: scrive la stringa s
nel file pf
pf.writeLines(S)
: scrive ciascun elemento della collezione di stringhe contenute in S
in una riga diversa del file pf
pf.close()
: chiude il file handler pf
ESERCIZIO 3: Si scriva una funzione che prenda in input un nome di un file, apra il file in lettura, e su ogni riga:
\n
. Suggerimento: usare la funzione replace()
"
split()
Infine la funzione deve restituire il numero di persone che nell'elenco hanno il secondo campo pari a 1. Si testi la funzione usando il file train.csv
che si trova nella cartella data
.
In [ ]:
def ReadAndCount(filename):
# DA COMPLETARE
return 0
print(ReadAndCount('data/train.csv'))
ESERCIZIO 4: Si scriva una funzione simile alla precedente, chiamata ReadAndPlotAge
, ma che restituisca una lista contenente l'èta di ciascun passegero (il sesto campo di ciascuna riga). Si usi tale lista per fare due plot (si vedano i notebook della seconda lezione e relativi esempi di uso di matplotlib con la funzione hist
):
Si testi la funzione usando il train.csv
.
In [ ]:
def ReadAndPlotAge(filename):
# DA COMPLETARE
# DA COMPLETARE
# DA COMPLETARE
pass
ESERCIZIO 5: Si scriva simile alla precedente, chiamata ReadAndPlotFare
, ma che usi il prezzo del biglietto invece dell'età dei passeggeri.
In [ ]:
def ReadAndPlotFare(filename):
# DA COMPLETARE
# DA COMPLETARE
# DA COMPLETARE
pass
ESERCIZIO 6: Si scriva una funzione, chiamata ReadAndPlot
, che generalizzi le due precedenti.
In [ ]:
def ReadAndPlot(filename):
# DA COMPLETARE
# DA COMPLETARE
# DA COMPLETARE
pass