Python conosce vari tipi di dati. Il tipo di una variabile viene ricavato dal valore che le viene assegnato. Nei linguaggi in cui un programma deve essere compilato prima di essere eseguito il tipo di ciascuna variabile deve essere dichiarato prima di assegnare alla variabile un valore. Python è un linguaggio interpretato i comandi vengono letti ed eseguiti sequenzialmente.
I tipi numerici built-in sono i numeri interi (integers, int), che possono essere anche rappresentati in base esadecimale, ottale o binaria, i numeri reali (floating point, float) e quelli complessi.
Una successione di cifre che non contenga il punto di separazione viene interpretato come un numero intero.
35**42
Sono numeri interi in base 16. Le cifre sono$\,$ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.
a = 0xf
int(a)
b = 1357
hex(b)
Una successione di cifre che contenga il punto di separazione viene interpretato come un numero reale. I numeri reali sono rappresentati in modo approssimato (10-14 cifre di precisione).
0.3
0.1*3
Numeri reali in notazione scientifica: $1.3\, 10^{-4}$ si scrive 1.3e-4.
a = 9.3e-4
b = 3.0e+17
a*b
Python, di default, scrive i numeri reali in formato non scientifico. Se vogliamo la risposta in notazione scientifica è necessario chiederlo esplicitamente (Maggiori informazioni più avanti.).
f"{a*b:e}"
In Python (come in Fortran e Matlab) i numeri complessi sono built-in. Qualche esempio:
x = 1.2 + 3.7j # Nessuno spazio fra il valore della parte immaginaria e il simbolo `j`
x
x.imag # Parte immaginaria
x.real # Parte reale
x * x.conjugate()
La sintassi per le operazioni fra numeri complessi è identica a quella per le operazioni fra numeri reali:
x * x
3 * x
Se si utilizza una variabile per la parte immaginaria, la notazione per costruire un numero complesso è:
a = 1.
b = -0.5
c = a + b*1j
print(c)
Per eseguire operazioni più complicate (come fare radici quadrate di numeri complessi etc) è nessario usare il modulo cmath
(Complex MATHematics):
import cmath
cmath.sqrt(x)
La funzione abs()
restituisce il valore assoluto o modulo di un numero:
a = -45.463
abs(a)
abs()
funziona anche per numeri complessi.
b = abs(1 + 2j)
b
b*b
Un'introduzione informale ai numeri. Python tutorial, section 3.1.1
Python Library Reference: una presentazione formale dei tipi numerici, http://docs.python.org/library/stdtypes.html#numeric-types-int-float-long-complex
Think Python, Sec 2.1
Stringhe, liste e ntuple (tuples) sono sequenze. Possono essere indicizzate e sezionate (sliced) nello stesso modo.
Tuples e stringhe sono “immutable” (fondamentalmente significa che non è possibile cambiare i singoli elementi in una ntupla, e non possiamo modificare i singoli caratteri all'interno di una stringa) mentre le liste sono “mutable” (cioè possiamo cambiare gli elementi di una lista.)
Le sequenze condividono le operazioni seguenti:
a[i] | restituisce l'*i*-esimo elemento di `a`; a[0] è il primo elemento |
a[i:j] | restituisce gli elementi da *i* fino a *j* − 1 |
len(a) | restituisce il numero di elementi nella sequenza |
min(a) | restituisce il valore più piccolo della sequenza |
max(a) | restituisce il valore più grande nella sequenza |
a.count(x) | restituisce il numero di volte in cui la sottosequenza x compare nella sequenza a |
x in a | restituisce `True` se `x` è un elemento di `a`, `False` in caso contrario |
a + b | concatena `a` e `b` |
n * a | concatena `n` copie della sequenza `a` |
Una stringa è una sequenza (immutable) di caratteri. Una stringa può essere definita usando single quotes:
a = 'Hello World'
double quotes:
a = "Hello World"
oppure triple quotes di entrambi i tipi
a = """Hello World"""
a = '''Hello World'''
Avere più delimitatori possibili per una stringa è utile quando un delimitatore è presente nella stringa. Esempio: supponiamo di voler assegnare alla variabile mystr la stringa L'ultimo dei Mohicani.
mystr = 'L'ultimo dei Mohicani'
mystr
mystr = "L'ultimo dei Mohicani"
mystr
La stringa vuota è:
""
Un particolare carattere può essere estratto usando il suo indice
a = 'trentatre'
a[2]
my_str = "abc"
print('Il primo carattere di my_str è: ',my_str[0])
print('Il secondo carattere di my_str è: ',my_str[1])
Il numero di caratteri in una stringa (la sua lunghezza) si ottiene con la funzione len()
:
a = "Hello Moon"
print('La lunghezza di "Hello Moon" è:',len(a))
b = ""
print('La lunghezza della stringa vuota è:',len(b))
Si possono combinare (“concatenare”) due stringhe usando l'operatore +
(è preferibile usare join
di cui parleremo più avanti):
'Hello ' + 'World'
Si possono anche concatenare due stringhe semplicemente scrivendole una accanto all'altra:
'a' 'b'
Sugli oggetti di Python possono agire metodi (legati a una classe), con la sintassi:
oppure funzioni, che si applicano con la notazione:
Un metodo particolarmente utile è split()
che converte una stringa in una lista di stringhe:
a = "This is a test sentence."
a.split()
Il meodo split()
divide le stringhe dove trova white space. White space significa qualsiasi carattere che viene stampato come spazio bianco, come uno spazio oppure più spazi consecutivi oppure il carattere tab.
È possibile passare una "separator string" a split()
, spezzando la stringa originaria sulls stringa di separazione (che viene eliminata). Per esempio,
per avere una lista di frasi complete si potrebbe usare il punto "." come separatore:
a = "The dog is hungry. The cat is bored. The snake is awake."
a.split(".")
Oppure:
a = "Pippo(--)Pluto(--)Paperino"
a.split("(--)")
Il metodo opposto per le stringhe è join
che si usa come segue:
a = "The dog is hungry. The cat is bored. The snake is awake."
s = a.split('.')
s
".".join(s) # join prende una lista come argomento
" STOP".join(s) # Si noti che la stringa comincia con uno spazio.
# Lo spazio dopo il separatore è lo spazio che segue il punto nel testo originale.
Per concatenare stringhe senza introdurre caratteri extra si può utilizzare la stringa vuota
:
''.join(['Nel',' ','mezzo',' ','del',' ','cammin',' ','di',' ','nostra',' ','vita'])
Non è possibile modificare direttamente gli elementi di una stringa (è immutabile
):
a = "This is a test sentence."
a[1] = 3
Ciononostante, le stringhe possiedono parecchi metodi utili che modificano la stringa di partenza. Per esempio upper()
restituisce una nuova stringa in cui tutti i caratteri della stringa iniziale diventano maiuscoli:
a.upper()
a
non viene modificata dall'applicazione di upper
che restituisce una nuova stringa:
a
È però sempre possibile assegnare la nuova stringa alla variabile precedente:
a = "Going Nowhere Fast"
a = a.upper()
a
Considerazioni analoghe valgono per replace
che sostituisce una sottostringa con un'altra:
b = "Stairways to Heaven"
b = b.replace("Heaven","Hell")
b
Una liste è una sequenza mutabile di oggetti. Gli oggetti possono essere di qualsiasi tipo, per esempio numeri interi:
a = [34, 12, 54]
a
o stringhe:
a = ['dog', 'cat', 'mouse']
a
Si può creare una lista anche con la funzione list
:
a = list('Micky Mouse')
a
['M', 'i', 'c', 'k', 'y', ' ', 'M', 'o', 'u', 's', 'e']
Una lista vuota è rappresentata da []
:
a = []
Come per le stringhe, il numero di elementi in una lista può essere trovato con la funzionelen()
:
a = ['dog', 'cat', 'mouse']
len(a)
È anche possibile mescolare tipi diversi nella stessa lista:
a = [123, 'duck', -42, 17, 0, 'elephant']
a
In Python una lista è un oggetto. È quindi possibile che una lista contenga delle altre liste perchè una lista contiene una sequenza di oggetti:
a = [1, 4, 56, [5, 3, 1], 300, 400]
Si possono combinare (“concatenare”) due liste usando l'operatore +
:
[3, 4, 5] + [34, 35, 100]
Si possono modificare gli elementi di una lista usando una assegnazione:
a = [1,2]
a
a = ["pippo",3.14,"pluto"]
a
Per accedere agli elementi di una lista:
a = ['a','b','c','d','e','f']
print(a[1])
print(a[2:4])
a[2] = 'f'
print(a)
Si può aggiungere un oggetto al fondo di una lista con il metodo append()
. Notate che append
modifica la lista su cui agisce e non restituisce nulla; come si dice, agisce "in place".
a = [34, 56, 23]
a.append(42)
a
Si può inserire un oggetto all'indice voluto in una lista con il metodo insert()
:
aList = [123, 'xyz', 'zara', 'abc']
aList.insert( 3, 2009)
print("Final List : ", aList)
Si può eliminare un oggetto da una lista chiamando il metodo remove()
e passandogli l'oggetto da eliminare. Per esempio:
a = [34, 56, 23, 42]
a.remove(56)
a
Ad una lista posso applicare il metodo pop
, che non ho menzionato. Per ottenere informazioni più dettagliate:
help(list.pop)
Gli elementi di una lista possono, a loro volta, essere liste in questo caso si parla di liste annidate o nested lists.
a_nest = [10,[20,21,22],30]
Per accedere agli elementi di una nested list:
a_nest[1]
a_nest[1][2]
Posso usare il metodo sort
oppure la funzione sorted
:
l = [1,3,2]
dir(l)
Il metodo sort
modifica la lista su cui opera e NON restituisce una lista risultato.
l.sort()
print(l)
La funzione sorted
non modifica la lista su cui viene fatta agire e restituisce una nuova lista
l1=sorted(l)
print(l1)
Il comando range(n)
genera la lista degli interi da 0 fino a n-1 (attenzione!), un tipo speciale di lista, che è spesso necessaria. Alcuni esempi:
list(range(3))
list(range(10))
Questo comando si usa spesso con i for loops
. Per esempio, per stampare i numeri 02,12,22,32,…,102, si può usare il codice seguente:
for i in range(11):
print(i**2)
Il comando range prende un parametro opzionale per l'inizio della sequenza di interi (start) e un altro parametro opzionale per il passo (step). Spesso si scrive range([start],stop,[step])
dove gli argomenti in parentesi quadrate (square brackets) (cioè start e step) sono opzionali.
Notate che il valore corrispondente a start
è il primo elemento presente nella lista, mentre il valore corrispondente a stop
è il "primo escluso" e non compare nella lista. Alcuni esempi:
list(range(3, 10)) # start=3
list(range(3, 10, 2)) # start=3, step=2
list(range(10, 0, -1)) # start=10,step=-1
list(range(0.,1.,0.1))
Perchè usiamo list(range())
?
In Python 3, range()
genera i numeri on demand. Quando si usa range()
in un for loop, questo è più efficiente, perchè non occupa memoria con una lista di numeri. Passare il comando range()
a list()
lo forza a generare immediatamente tutti i numeri.
A ntupla (tuple) è una sequenza (immutable) di oggetti. Le ntuple si comportano in modo molto simile alle liste con l'eccezione che non possono essere modificate.
Per esempio, qualunque tipo di oggetto vi può comparire:
a = (12, 13, 'dog')
a
a[0]
Le parentesi non sono necessarie per definire una tuple: una sequenza di oggetti separati da virgole è sufficiente a definire una tuple:
a = 100, 200, 'duck'
a
benchè sia buona pratica includere le parantesi per una maggiore leggibilità.
Si può costruire una ntuple con applicando il comando tuple ad una sequenza:
tuple([1,'a'])
tuple("abc")
Tuples possono anche essere usate per assegnare due valori contemporameamente:
x, y = 10, 20
x
y
Le ntuple possono essere usate per scambiare due oggetti in una sola riga di codice. Per esempio:
x = 1
y = 2
x, y = y, x
x
y
La ntupla vuota è ()
.
t = ()
len(t)
type(t)
La notazione per una ntupla contenente un solo valore può, all'inizio, sembrare un po' strana:
t = (42,)
type(t)
len(t)
La virgola addizionale è necessaria per distinguere (42,)
da (42)
. Nel secondo caso le parentesi indicherebbero solo l'ordine di precedenza delle operazioni: (42)
si semplifica a 42
che è semplicemente un numero:
t = (42)
type(t)
Un esempio dell'immutabilità di una tuple:
a = (12, 13, 'dog')
a[2]
a[0] = 1
Operazioni possibili sulle ntuple
dir(a)
len(a)
a.index(13)
L'immutabilità è la differenza principale fra una tuple e una lista (che è mutable). Le tuples vengono utilizzate quando non si vuole che il contenuto venga modificato.
Le funzioni Python che ritornano più di un valore, li ritornano in tuples (che è sensato perchè in genere non si vuole che i risultati di una chiamata a una funzione vengano modificati).
Abbiamo già accennato più volte all'uso degli indici in sequenze introducendo le varie strutture dati. Questa sezione cerca di sistematizzare l'argomento.
I singoli oggetti in una lista/stringa/tuple possono essere indicati con il loro indice fra parentesi quadre([
e ]
). Notate che Python (come in C ma diversamente dal Fortran e da Matlab) conta gli indici partendo da zero!
a = ['dog', 'cat', 'mouse']
a[0]
a[1]
a[2]= 'parrot'
a
L'indice di un oggetto in una sequenza si può trovare con il metodo index
(oppure find
, cercate sulladocumentazione la differenza fra i due metodi):
a.index('cat')
b = [0,'pluto',10,3]
b.index(10)
Python ha un modo semplice per estrarre l'ultimo elemento di una lista: si usa l'indice “-1”, dove il segno meno indica che l'elemento è a un passo dal fondo della lista. Nello stesso, l'indice “-2” ritorna il penultimo elemento (2nd last):
a = ('dog', 'cat', 'mouse')
a[-1]
a[-2]
Si può anche pensare ad a[-1]
come una abbreviazione di a[len(a) - 1]
.
Ricordate che le stringhe (come le liste) sono delle sequenze e possono essere indicizzate nello stesso modo:
a = "Hello World!"
a[0]
a[1]
a[100]
a[-1]
a[-2]
a[3]='u'
Lo slicing di una sequenze può essere utilizzato per estrarre più di un elemento. Per esempio:
a = "Hello World!"
a[5:10]
Scrivendo a[0:3]
richiediamo i primi 3 elementi iniziando dall'elemento 0. Analogamente:
a[1:4]
a[0:2]
a[0:6]
Si possono usare indici negtivi per riferirsi alla fine della sequenza:
a[0:-1]
Per arrivare fino alla fine della sequenza:
a[5:len(a)]
È anche possibile omettere l'indice inziale o quello finale e questo restitusce tutti gli elementi a partire dall'inizio oppure fino alla fine della sequenza. Qualche esempio per chiarire:
a = "Hello World!"
a[:5]
a[5:]
a[-2:]
a[:]
Per invertire l'ordine degli elementi di una lista possiamo usare:
a[::-1]
Notate che a[:]
genera una copia di a
. Il modo con cui vengono usati gli indici nello slicing può sembrare controintuitivo. Se vi trovate in difficoltà, ricordate questa spiegazione dal Python tutorial (section 3.1.2):
The best way to remember how slices work is to think of the indices as pointing between characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of 5 characters has index 5, for example:
0 1 2 3 4 <-- use for INDEXING -5 -4 -3 -2 -1 <-- use for INDEXING from the end +---+---+---+---+---+ | H | e | l | l | o | +---+---+---+---+---+ 0 1 2 3 4 5 <-- use for SLICING -6 -5 -4 -3 -2 -1 <-- use for SLICING from the end
The first row of numbers gives the position of the slicing indices 0...5 in the string; the second row gives the corresponding negative indices. The slice from i to j consists of all characters between the edges labelled i and j, respectively.
L'affermazione importante è che nello slicing gli indici puntano fra i caratteri o elementi.
Per indicizzare è preferibile pensare che gli indici si riferiscano direttamente agli elementi.
Se non vi ricordate esattamente come funzionano gli indici, potete semplicemente sperimentare con un piccolo esempio usando il Python prompt prima o durante la scrittura del vostro programma.
a = "Hello"
a[-3:-6:-1]
La posizione di un elemento in qualunque oggetto di tipo sequenza può essere trovato con il metodo index:
(1,2,3).index(2)
Se l'elemento cercato non è presente si ha un errore:
[1,2,3].index(4)
I dizionari sono anche chiamati “associative arrays” o “hash tables”. I dizionari sono insiemi unordered di coppie key-value. Le keywords devono essere oggetti immutabili mentre i dizionari sono oggetti mutabili.
Un dizionario vuoto può essere creato usando parentesi graffe (curly braces):
d = {}
print(d)
Coppie keyword-value possono essere aggiunti come segue:
d['today'] = '22 deg C' # 'today' è la keyword
d['yesterday'] = '19 deg C'
print(d)
Il valore può essere estratto usando la keyword come indice:
d['today']
Altri modi di riempire un dizionario se i dati sono noti al momento in cui viene creato sono:
d2 = {2:4, 3.5:9, 4:16, 5:25} # Notate che sto usando dei numeri interi o reali come chiavi.
d2
d2_a = {'p':4, 'q':9, 'r':16, 's':25} # Se uso stringhe come chiavi devo scriverli fra apici
d2_a
oppure:
d3 = dict(a=1, b=2, c=3) # In questo caso, se uso stringhe come chiavi NON devo scriverli fra apici
# In questo caso, non posso usare numeri interi o reali come chiavi.
d3
Morale della favola: se esistono più modi di dare un comando non è garantito che ci sia una ovvia coerenza fra i diversi modi.
La funzione dict()
crea un dizionario vuoto.
Per eliminare una coppia key-value da un dizionario si può usare del
passando la key come argomento:
dd = {'p':4, 'q':9, 'r':16, 's':25}
print(dd)
del dd['r']
print(dd)
d.keys()
restituisce la lista di tutte le keys:
d.keys()
Altri metodi utili per i dizionari sono values()
, items()
e get()
.
type(d.values())
d.items()
Il metodo get(key,default)
restituisce il valore corrispondente a una certa key
se la key esiste, altrimenti restituisce l'oggetto di default
.
d.get('today','unknown')
d.get('tomorrow','unknown')
'today' in d
'tomorrow' in d
Si può usare in
per controllare se una certa chiave è presente:
d ={'pippo':'pluto'}
'pippo' in d
'pluto' in d
Per controllare se è presente un certo valore si può in
sulla lista dei valori
'pluto' in d.values()
Ulteriori dettagli:
La keyword può essere qualsiasi (immutable) oggetto in Python. Questo include:
numeri
stringhe
tuples.
i dizionari restituiscono i valori molto velocemente quando viene loro fornita la key.
vlist = [1.2,-0.3,3.5]
Componente y
:
vlist[1]
Rappresentazione con un dizionario:
vdict = {'vx':1.2, 'vy':-0.3, 'vz':3.5}
Componente y
:
vdict['vy']
I valori di un dizionario possono essere a loro volte dizionari (oppure liste e ntuple):
nazioni = {'Francia':{'capitale':'Parigi','popolazione':67.39e6},
'Germania':{'capitale':'Berlino','popolazione':83.24e6}}
nazioni['Germania']
nazioni['Germania']['popolazione']
La funzione type
mostra il tipo di un oggetto. È possibile convertire un oggetto in uno di tipo diverso.
La funzione int()
converte in qualunque oggetto trasformabile in un intero:
a = '34' # a è una stringa che contiene i caratteri 3 e 4
x = int(a) # x è il numero intero 34
print("Il type di '34' è",type(a))
print("Il type di",x," è",type(a))
Ovviamente l'argomento di int
deve essere interpretabile come un intero
int('piripacchio')
Agendo su numeri reali int()
tronca qualsiasi parte non intera:
int(7.0)
int(7.9)
int(-7.9)
Per arrotondare un numero reale all'intero più vicino usate la funzione round()
:
round(7.9)
round(-7.9)
Il tipo di una stringa è str
. La funzione str
trasforma un oggetto in stringa:
a = "Hello World"
type(a)
b = ""
type(b)
num = 5.76
print(type(num))
num_as_string = str(num)
print("num_as_string is of type",type(num_as_string))
Il tipo di una lista è list
:
a = [34, 12, 54]
type(a)
type([])
Python fornisce la funzione id()
che restituisce un numero che identifica in modo unico un oggetto, essenzialmente l'indirizzo in memoria. Possiamo utilizzare questa funzione per verificare se due oggeti sono identici, cioè se si riferiscono alla stessa locazione di memoria.
m = 2
print(f'id(m) = {id(m)}')
Quando eseguiamo il comando n = m
, la variabile n
punta alla stessa posizione di memoria:
n = m
print(f'id(n) = {id(n)}')
Usando is
In Python, i numeri, le ntuple, le stringhe sono "immutabili" cioè non possono essere modificati senza creare una nuova copia dell'oggetto.
Se cambiamo il valore di n cambia anche la posizione in memoria:
n += 1
print(f'n = {n}')
print(f'id(n) = {id(n)}')
L'indirizzo che è immagazzinato nella variabile m, invece, non cambia:
print(f'm = {m}')
print(f'id(m) = {id(m)}')
Copia di liste tramite assegnazione. Qualche esempio:
a = list(range(10))
a
b = a # shallow copy. b punta allo stesso oggetto a cui punta a
b[0] = 42
a # cambiare b cambia anche a
id(a)
id(b)
id(b[0])
Per creare una nuova copia indipendente di una sequenza di oggetti (incluse le liste), possiamo usare lo slicing. Se a
è una lista, allora a[:]
restituisce una copia indipendente di a
.
c = a[:]
id(c) # c è un oggetto diverso
c[0] = 100
a # cambiare c non cambia a
c # verifichiamo c
La standard library di Python fornisce il modulo copy
, che contiene funzioni che possono essere utilizzate per creare copie di oggetti. Avremmo potuto usare import copy; c = copy.deepcopy(a)
invece di c = a[:]
.
st = "abc"
Non posso sostitire una lettera in st
st[0] = 'A'
Posso però fare
st = st.upper()
st
Il metodo upper crea una nuova stringa. Quando la assegno a st
distruggo la referenza all'oggetto originale.
st = "abc"
print(id(st))
st = st.upper()
print(id(st))
La stessa cosa succede con ntuple e numpy.array.
Se modifico un oggetto mutabile la sua locazione in memoria non viene cambiata.
lst = [1,2,3]
print(lst,id(lst))
lst[0] = 100
print(lst,id(lst))
lst.append(44)
print(lst,id(lst))