Python Base¶

Python Biella Group¶


Prima serata, 3/10/2022¶

Speaker:

  • David Leoni (Università di Trento - DISI, Dip. Informatica)
  • david.leoni@unitn.it

Repository github per questi tutorial:

  • https://github.com/PythonBiellaGroup/PythonBase/tree/main/teoria

Materiale tratto dal libro SoftPython

  • (Per anteprima slide premi Esc)

image.png

Script e notebooks¶

Il codice Python si può normalmente trovere in file con estensione:

  • .py: semplici file di testo, es math.py
    • Detti anche script o moduli
  • .ipynb: notebook Jupyter interattivi come questo, che contengono celle con l'output

Riferimenti: SoftPython - Strumenti e script

Che fare¶

  • Scarica il notebook parte1.ipynb in una cartella
  • Apri la app Jupyter Notebook, si dovrebbe aprire un browser con una lista di file: navigala e apri notebook
  • Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte ESERCIZIO, che ti chiederanno di scrivere dei comandi Python nelle celle successive.

ATTENZIONE: In questo tutorial usiamo SOLO PYTHON 3

Se per caso ottieni comportamenti inattesi, controlla di usare Python 3 e non il 2. Se per caso il tuo sistema operativo scrivendo python fa partire il 2, prova ad eseguire il tre scrivendo il comando: python3

Scorciatoie da tastiera per utenti Windows e Linux:

  • Per eseguire il codice Python dentro una cella di Jupyter, premi Ctrl+Invio
  • Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi Shift+Invio
  • Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi Alt+Invio
  • Se per caso il Notebook sembra inchiodato, prova a selezionare Kernel -> Restart

Se sei un utente Mac, sostituisci i tasti sopra con i seguenti:

  • Ctrl -> Command ⌘
  • Shift -> Shift ⇧
  • Alt -> Option ⌥

Proviamo Jupyter 1/2¶

Vediamo brevemente come funzionano i fogli Jupyter.

ESERCIZIO: Proviamo a inserire un comando Python: scrivi nella cella qua sotto l'espressione 3 + 5, e poi mentre sei in quella cella premi i tasti speciali Control+Invio. Un'espressione produce sempre un risultato, in questo caso dovresti vedere apparire il numero 8

ESERCIZIO: in Python possiamo scrivere commenti iniziando una riga con un cancelletto #. Come prima, scrivi nella cella sotto 3 + 5 ma questa volta scrivilo nella riga sotto la scritta # scrivi qui:

ESERCIZIO: Jupyter per ogni cella mostra il risultato solo dell'ultima riga eseguita in quella cella. Prova a inserire questo codice nella cella sotto ed esegui premendo Control+Invio. Che risultato appare?

3 + 5
1 + 1

Proviamo Jupyter 2/2¶

ESERCIZIO: a) Prova adesso a inserire questo codice nella cella sotto ed esegui premendo Control+Invio. Che risultato appare?

print(3 + 5)
print(1 + 1)

b) E così cosa stamperà?

print(3 + 5)
1 + 1
3 + 4

ESERCIZIO: Proviamo adesso a creare noi una nuova cella.

  • Mentre sei con il cursore in questa cella, premi Alt+Invio. Si dovrebbe creare una nuova cella dopo la presente.

  • Nella cella appena creata, inserisci 2 + 3 e poi premi Shift+Invio. Cosa succede al cursore? Prova la differenze con Control+Invio. Se non capisci la differenza, prova a premere ripetutamente Shift+Invio e vedi che succede.

Variabili e stampa¶

Per creare una variabile è sufficiente assegnarle direttamente un valore

In [3]:
fiori = 5

(volendo potremmo anche dichiarare il tipo ma non è necessario)

Per stampare sequenze di caratteri:

In [4]:
print("La mattina abbiamo raccolto", fiori, "fiori")
La mattina abbiamo raccolto 5 fiori

Per aggiornare delle variabili le puoi riassegnare:

In [5]:
fiori = 5
print("La mattina abbiamo raccolto", fiori, "fiori")
rose_rosse = 3
print("Pomeriggio abbiamo raccolto altre", rose_rosse, "rose")
fiori = fiori + rose_rosse
print("Adesso abbiamo", fiori, "fiori.")
La mattina abbiamo raccolto 5 fiori
Pomeriggio abbiamo raccolto altre 3 rose
Adesso abbiamo 8 fiori.

Assegnazione multipla¶

Possiamo inizializzare più variabili su una sola linea così separandole con virgole:

In [6]:
libri, quaderni = 3,7

print("Ho comprato", libri, "libri e", quaderni, "quaderni.")
Ho comprato 3 libri e 7 quaderni.

Principali tipi di dati Python¶

Tipo Valore 'vuoto' Esempio Altro esempio Mutabilità Nota
int 0 3 -5 immutabili possono essere arbitrariamente grandi
float 0.0 3.7 -2.3 immutabili numeri in virgola mobile
bool False True immutabili
str "" "Buon giorno" 'come stai?' immutabili
tuple () (5, 7, 10, 7) ("qualcosa", 5, "altro ancora") immutabili
list [] [5, 7, 10, 7] ["qualcosa", 5, "altro ancora"] mutabili
set set() {7, 5, 10} {"altro ancora", "qualcosa", 5} mutabili
dict {} {'limoni':4, 'arance':7} {'lampada':'illumina', 'termosifone':'scalda'} mutabili
NoneType None

Riferimenti: SoftPython, Fondamenti - Tipi di dati

Numeri interi e con virgola¶

Riferimenti: SoftPython - Tipi di dato - Basi

In Python abbiamo numeri interi:

In [7]:
3 + 5
Out[7]:
8

La somma tra interi ovviamente ci da un intero:

In [8]:
type(3 + 5)
Out[8]:
int

E se dividiamo interi? Ci troveremo con il tipo in virgola mobile float:

In [9]:
15 / 4
Out[9]:
3.75
In [10]:
type(15 / 4)
Out[10]:
float

ATTENZIONE al punto !

In Python e in molti formati dati, al posto della nostra virgola si usa il formato inglese con il punto .

In [11]:
15 // 4   # divisione intera
Out[11]:
3

Booleani - bool¶

I booleani rappresentano valori veri e falsi, e si possono usare per verificare quando certe condizioni avvengono.

Riferimenti

  • SoftPython Basi - booleani
  • (SoftPython Controllo di flusso - if)

I booleani sono usati nell'algebra booleana e hanno il tipo bool.

I valori di verità sono rappresentati in Python con le parole chiave True e False:

In [12]:
x = True
In [13]:
type(x)
Out[13]:
bool
In [14]:
y = False

Operatori tra booleani¶

Possiamo operare sui valori booleani con gli operatori booleani not, and, or:

and

a b a and b
False False False
False True False
True False False
True True True

or¶

a b a or b
False False False
False True True
True False True
True True True

not¶

a not a
False True
True False

Conversione e valori logici¶

Ogni oggetto ha associato un valore logico, e pertanto può essere convertito in un booleano usando bool come una funzione.

In generale, gli oggetti:

  • considerati 'vuoti' hanno corrispondente valore logico False
  • quelli 'non vuoti' hanno valore logico True

Ogni tipo di oggetto ha un solo valore considerato 'vuoto'.

Quale sarà il valore 'vuoto' per gli interi?

Che sia il famoso zero 0 ?

In [15]:
bool(0)     # Trovato!
Out[15]:
False

Tutti gli altri interi essendo considerati 'non vuoti' quando convertiti ci daranno valore logico True:

In [16]:
bool(1)
Out[16]:
True
In [17]:
bool(72)
Out[17]:
True
In [18]:
bool(-5)
Out[18]:
True

Pensiamo alle stringhe.

Quale stringa avrà il valore logico False?

La stringa 'vuota'! Ce n'è una sola:

In [19]:
bool("")
Out[19]:
False

Qualunque altra stringa ci darà il valore True:

In [20]:
bool("lampadario")
Out[20]:
True

E una stringa di soli spazi " "?

In [21]:
bool("      ")   
Out[21]:
True

Per fare una conversione verso un tipo di destinazione:

Usa il nome del tipo come se fosse una funzione

Esempio conversione da booleano a intero:

In [22]:
int(True)
Out[22]:
1
In [23]:
int(False)
Out[23]:
0

Attenzione a:

  • Se Python vede un oggetto in un'espressione booleana, cerca automaticamente di convertirlo in un booleana
  • Ordine di valutazione espressioni booleane

Operatori di comparazione¶

Gli operatori di comparazione permettono di costruire espressioni che ritornano un valore booleano:

Comparatore Descrizione
a == b True se e solo se a = b
a != b True se e solo se a $\neq$ b
a < b True se e solo se a < b
a > b True se e solo se a > b
a <= b True se e solo se a $\leq$ b
a >= b True se e solo se a $\geq$ b
In [24]:
3 == 3
Out[24]:
True
In [25]:
3 == 5
Out[25]:
False
In [26]:
3 != 5  
Out[26]:
True
In [27]:
3 < 5
Out[27]:
True
In [28]:
5 <= 5
Out[28]:
True

Le comparazioni sono espressioni che producono booleani

-> possiamo anche assegnare il risultato ad una variabile:

In [29]:
x = 5 > 3
In [30]:
print(x)
True

Congiungere comparazioni¶

Data un paio di quantità:

In [31]:
x, y = 7, 5

Come verificare se x e y sono entrambe maggiori di zero?

Il modo corretto (per quanto un po' verboso) è il seguente:

In [32]:
x > 0 and y > 0
Out[32]:
True

ATTENZIONE: la seguente scrittura invece NON è corretta:

x and y > 0    # SBAGLIATO!
In [33]:
-5 and 3 > 0
Out[33]:
True

Stringhe - str¶

Le stringhe sono sequenze immutabili di caratteri.

Riferimenti - SoftPython:

  • stringhe 1 - introduzione
  • stringhe 2 - operatori
  • stringhe 3 - metodi di base
  • stringhe 4 - metodi di ricerca

Python offre diversi operatori per lavorare con le stringhe:

Operatore Uso Risultato Significato
len len(str) int Ritorna la lunghezza della stringa
concatenazione str1 + str2 str Concatena due stringhe
inclusione str1 in str2 bool Controlla se la stringa è presente in un'altra stringa
indice str[int] str Legge il carattere all'indice specificato
slice str[int:int] str Estrae una sotto-stringa
uguaglianza ==,!= bool Controlla se due stringhe sono uguali o differenti
replicazione str * int str Replica la stringa

Lunghezza¶

Per ottenere la lunghezza di una lista, possiamo usare la funzione len:

In [34]:
len('legna')
Out[34]:
5

Leggere un carattere¶

Una stringa è una sequenza di caratteri

la posizione dei caratteri nella sequenza inizia da 0

Come accedere al carattere in posizione 2?

In [35]:
#0123
'ciao'[2]
Out[35]:
'a'

Slice¶

Come leggere solo una sottosequenza che parte da un una posizione ad un'altra?

Basta indicare delle quadre [ ] con:

  • indice di partenza incluso
  • : come separatore
  • indice di fine escluso
In [36]:
         #0123456789
parola = 'mercantile' 
In [37]:
estratta = parola[3:8]  
In [38]:
estratta
Out[38]:
'canti'
In [39]:
parola
Out[39]:
'mercantile'

NOTA: la stringa estratta è completamente NUOVA e slegata dall'originale:

In [40]:
         #0123456789
parola = 'mercantile'

estratta = parola[3:8]   
In [41]:
parola = "peschereccio"
In [42]:
print(estratta)
canti

Concatenare stringhe¶

Una delle cose che si fanno più frequentemente è concatenare delle stringhe:

In [43]:
"ciao " + "mondo"
Out[43]:
'ciao mondo'

Formattare stringhe¶

Attenzione a quando concateniamo una stringa e un numero

"ciao " + 7

Python si arrabbia:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-38-e219e8205f7d> in <module>()
----> 1 "ciao " + 7

TypeError: Can't convert 'int' object to str implicitly

Bisogna convertire esplicitamente il numero (in genere, qualunque oggetto) in una stringa

Per concatenerare oggetti che non sono stringhe:

Modo 1: usare la funzione str come qui:

In [44]:
"ciao " + str(7)
Out[44]:
'ciao 7'

Modo 2 (meglio): usare l'operatore di formattazione percentuale %

  • sostituisce alle occorrenze di %s quello che mettete dopo un % dopo la stringa
In [45]:
"ciao %s" % 7
Out[45]:
'ciao 7'

%s può stare all'interno della stringa e venire ripetuto.

Per ogni occorrenza si può passare un sostituto diverso, come per esempio nella tupla ("bello", "Python")

In [46]:
"Che %s finalmente imparo %s" % ("bello", "Python")
Out[46]:
'Che bello finalmente imparo Python'

Formattare con le f-string¶

Modo 3 (il migliore) le f-string si costruiscono anteponendo f alla stringa e inserendo dentro la stringa delle graffe con le espressioni di cui vogliamo vedere il risultato.

In [47]:
x = 3
y = 5
s = "Fantastico"

#  Nelle stringhe di formattazione possiamo mettere...
print( f"Metto variabili: {x} e anche espressioni: {x + y}. {s}!" )
Metto variabili: 3 e anche espressioni: 8. Fantastico!

Riassegnare stringhe 1/2¶

Le stringhe sono immutabili...

...quindi tentare di sovrascrivere un carattere porta ad un errore:

#01234
s = 'ciao'

s[2] = 'b'  # SBAGLIATO!
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-113-e5847c6fa4bf> in <module>
----> 1 s[2] = 'b'

TypeError: 'str' object does not support item assignment

Riassegnare stringhe 2/2¶

Quello che si può fare è cambiare l'associazione della variabile

Generiamo una nuova stringa prendendo pezzi dall'originale:

In [48]:
s = 'ciao'
s = s[0] + s[1] + 'b' + s[3]
In [49]:
s
Out[49]:
'cibo'

Il vecchio oggetto 'ciao' non essendo più raggiungibile da nessuna variabile, prima o poi verrà automaticamente marcato da Python come oggetto eliminabile dalla memoria tramite la cosiddetta garbage collection.

Usare metodi degli oggetti¶

In Python quasi tutto è un oggetto

Ogni tipo di oggetto ha delle azioni chiamati metodi che si possono eseguire su quello oggetto

Per esempio, ogni stringa è un oggetto di tipo str

Stringhe - Metodi base¶

Metodo Risultato Significato
str.upper() str Ritorna la stringa con tutti i caratteri maiuscoli
str.lower() str Ritorna la stringa con tutti i caratteri minuscoli
str.capitalize() str Ritorna la stringa con il primo carattere maiuscolo
str1.startswith(str2) bool Controlla se la stringa inizia con un'altra
str1.endswith(str2) bool Controlla se la stringa finisce con un'altra
str1.isalpha(str2) bool Controlla se tutti i caratteri sono alfabetici
str1.isdigit(str2) bool Controlla se tutti i caratteri sono cifre
str.isupper() bool Controlla se tutti i caratteri sono minuscoli
str.islower() bool Controlla se tutti i caratteri sono maiuscoli

Riferimenti: SoftPython - Stringhe 3

Data una stringa che rappresenta un nome come "trento"...

quale metodo potremmo usare per rendere in maiuscolo la prima lettera?

Proviamo il metodo esistente capitalize()

(nota: la stringa è tutta in minuscolo e capital in inglese vuol anche dire 'maiuscolo' )

In [50]:
"trento".capitalize()
Out[50]:
'Trento'

Stringhe - Metodi di ricerca¶

Metodo Risultato Significato
str1.strip(str2) str Rimuove stringhe dai lati
str1.lstrip(str2) str Rimuove stringhe da sinistra
str1.rstrip(str2) str Rimuove stringhe da destra
str1.count(str2) int Conta il numero di occorrenze di una sottostringa
str1.find(str2) int Ritorna la prima posizione di una sottostringa a partire da sinistra
str1.rfind(str2) int Ritorna la prima posizione di una sottostringa a partire da destra
str1.replace(str2, str3) str Sostituisce sottostringhe

Riferimenti: SoftPython - Stringhe 4

ATTENZIONE: i metodi delle stringhe generano stringhe SEMPRE NUOVE

L’oggetto stringa originale non viene MAI modificato.

Esempio metodo stringhe: replace¶

In [51]:
originale = "PARLARE E BRINDARE"

risultato = originale.replace('ARE', 'IAMO')  
In [52]:
risultato
Out[52]:
'PARLIAMO E BRINDIAMO'
In [53]:
originale
Out[53]:
'PARLARE E BRINDARE'

Liste - list¶

Una lista in python è una sequenza mutabile di elementi eterogenei, in cui possiamo mettere gli oggetti che vogliamo.

Riferimenti - SoftPython:

  • Liste 1 - introduzione
  • Liste 2 - operatori
  • Liste 3 - metodi base
  • Liste 4 - metodi di ricerca

Creiamo una lista di stringhe:

In [54]:
lista = ["ciao", "soft", "python"]
In [55]:
lista
Out[55]:
['ciao', 'soft', 'python']

Le liste sono sequenze di oggetti possibilmente eterogenei...

quindi dentro ci potete buttare di tutto, interi, stringhe, duplicati, altre liste, ...:

In [56]:
cose = ["ciao", 97, "ciao", ["a","b"] ]
In [57]:
cose
Out[57]:
['ciao', 97, 'ciao', ['a', 'b']]

Liste - operatori¶

Per manipolare le liste vi sono diversi operatori. I seguenti si comportano come quelli visti per le stringhe.

Operatore Use Risultato Significato
len len(lst) int Ritorna la lunghezza di una lista
indice list[int] obj Legge/scrive un elemento all'indice specificato
slice list[int:int] list Estrae una sotto-lista - ritorna una NUOVA lista
inclusione obj in list bool Controlla se un elemento è presente in una lista
concatenazione list + list list Concatena due liste - ritorna una NUOVA lista
aggregazione max(lst) int Data una lista di numeri, ritorna il massimo
aggregazione min(lst) int Data una lista di numeri, ritorna il minimo
aggregazione sum(lst) int Data una lista di numeri, li somma tutti
replicazione list * int list Replica la lista - ritorna una NUOVA lista
uguaglianza ==,!= bool Controlla se due liste sono uguali o differenti

Riferimenti: SoftPython - liste 2

Per accedere ad un elemento usiamo un indice (come per per le stringhe):

In [58]:
        #   0      1         2 
lista = ["ciao", "soft", "python"]
lista[1]
Out[58]:
'soft'

In una lista possiamo MODIFICARE le celle con l'assegnazione:

In [59]:
lista[1] = "SOFT"
In [60]:
lista
Out[60]:
['ciao', 'SOFT', 'python']

Liste - slice¶

Possiamo estrarre sottosequenze con le slice, come per le stringhe:

In [61]:
#     0  1  2  3  4  5  6  7  8  9
la = [40,30,90,80,60,10,40,20,50,60]
lb = la[3:7]

print(lb)
[80, 60, 10, 40]

ATTENZIONE: l'estrazione produce una NUOVA lista

se modifichiamo l'originale non vedremo alcun cambiamento nella stringa estratta:

In [62]:
la[3] = 999
In [63]:
print(la)
[40, 30, 90, 999, 60, 10, 40, 20, 50, 60]
In [64]:
print(lb)   
[80, 60, 10, 40]

Liste - Metodi di base¶

Metodo Ritorna Descrizione
list.append(object) None Aggiunge un nuovo elemento alla fine della lista
list.extend(list) None Aggiunge diversi nuovi elementi alla fine della lista
list.insert(int,object) None Aggiunge un nuovo elemento a qualche posizione data
list.pop() object Rimuove e ritorna l'elemento all'ultima posizione
list.pop(int) object Dato un indice, rimuove e ritorna l'elemento a quella posizione
list.reverse() None Inverte l'ordine degli elementi
list.sort() None Ordina gli elementi
"sep".join(seq) str produce una stringa concatenando tutti gli elementi in seq separati da "sep"

Riferimenti: SoftPython - liste 3

I METODI DELLE LISTE MODIFICANO LA LISTA SU CUI VENGONO CHIAMATI !

Quando chiami un metodo di una lista (l'oggetto a sinistra del punto .), MODIFICHI la lista stessa (diversamente dai metodi sulle stringhe che generano sempre una nuova stringa senza cambiare l'originale)

ATTENZIONE: I METODI DELLE LISTE NON RITORNANO NULLA!

Quasi sempre ritornano l'oggetto None (diversamente da quelli delle stringhe che ritornano sempre una nuova stringa)

Liste: append¶

Possiamo aggiungere elementi alla fine di una lista usando il comando append:

In [65]:
parole = []
In [66]:
parole.append("ciao")
In [67]:
parole
Out[67]:
['ciao']
In [68]:
parole.append("soft")
parole.append("python")
In [69]:
parole
Out[69]:
['ciao', 'soft', 'python']

Esempio: ordinamento liste¶

Le liste si possono ordinare comodamente con il metodo .sort

  • funziona su tutti gli oggetti ordinabili.

Proviamo i numeri:

In [70]:
lista = [ 8, 2, 4]

lista.sort()
In [71]:
lista
Out[71]:
[2, 4, 8]

Proviamo ad ordinare delle stringhe:

In [72]:
parole = [ 'mondo', 'python',  'ciao',]

parole.sort()
parole
Out[72]:
['ciao', 'mondo', 'python']

Per generare una nuova lista invece di modificare l'originale, c'è sorted()

NOTA: sorted è una funzione, non un metodo:

In [73]:
parole = [ 'mondo', 'python', 'ciao',]

sorted(parole)
Out[73]:
['ciao', 'mondo', 'python']
In [74]:
# la lista originale non è cambiata:
parole
Out[74]:
['mondo', 'python', 'ciao']

Ordine rovesciato

Possiamo indicare in fondo il parametro opzionale reverse e il suo valore, che in questo caso sarà True:

In [75]:
sorted(['mondo', 'python', 'ciao'], reverse=True)
Out[75]:
['python', 'mondo', 'ciao']

Rovesciare liste non ordinate

E se volessimo rovesciare una lista così com'è, senza ordinarla in senso decrescente, per esempio per passare da[6,2,4] a [2,4,6]?

Cercando nella libreria di Python,troviamo una comoda funzione reversed() che prende come paramatro la lista che vogliamo rovesciare e ne genera una nuova rovesciata:

In [76]:
reversed([6,2,4])
Out[76]:
<list_reverseiterator at 0x7f47b8f59290>

Problema: reversed produce una sequenza 'congelate', che va materializzata convertendola esplicitamente a lista così:

In [77]:
list(  reversed([6,2,4]) )
Out[77]:
[4, 2, 6]

Liste - Metodi di ricerca¶

Metodo Ritorna Descrizione
list.count(object) int Conta le occorrenze di un elemento
list.index(object) int Trova la prima occorrenza di un elemento e ne ritorna la posizione
list.remove(object) None Rimuove la prima occorrenza di un elemento
str1.split(str2) list Produce una lista con tutte le parole in str1 separate da str2

ATTENZIONE: spesso questi metodi vengono abusati portando a codice incorretto / inefficiente, usali con giudizio!

Riferimenti: SoftPython - liste 4

Tuple - tuple¶

Una tupla in Python è una sequenza immutabile di elementi eterogenei che ammette duplicati

  • perciò possiamo mettere gli oggetti che vogliamo
  • ... di tipi diversi
  • ... e ripetuti

Le tuple si creano con le parentesi tonde () e separando gli elementi da virgole ,.

Qualche esempio:

In [78]:
numeri = (6,7,5,7,7,9)
In [79]:
print(numeri)
(6, 7, 5, 7, 7, 9)
In [80]:
roba = (4, "carta", 5, 2,"scatole", 7)   # tupla eterogenea

EVITA di mettere oggetti mutabili dentro le tuple!

Per creare una tupla di un solo elemento: aggiungi una virgola dopo l'ultimo elemento:

In [81]:
tuplina = (4,)  # occhio alla virgola !!!
In [82]:
type(tuplina)
Out[82]:
tuple

Per vedere la differenza, scriviamo qua sotto (4) senza virgola:

In [83]:
farlocca = (4)
In [84]:
type(farlocca)
Out[84]:
int

Vediamo che farlocca è un int...

  • il 4 è stato valutato come un'espressione dentro delle tonde e il risultato è il contenuto delle tonde!

Tupla vuota¶

In [85]:
vuota = ()
In [86]:
print(vuota)
()
In [87]:
type(vuota)
Out[87]:
tuple

Tuple senza parentesi¶

Per assegnare dei valori a delle variabili è possibile usare una notazione del genere,

in cui a sinistra dell' = mettiamo nomi di variabili e a destra una sequenza di valori:

In [88]:
a,b,c = 1, 2, 3
In [89]:
b
Out[89]:
2

Se ci chiediamo cosa sia quel 1,2,3, possiamo provare a mettere a sinistra solo una variabile:

In [90]:
# ATTENZIONE: MEGLIO EVITARE !
x = 1,2,3
In [91]:
type(x)
Out[91]:
tuple

Vediamo che Python ha considerato quel 1,2,3 come una tupla.

Attenzione: Se trovi strane tuple durante l'esecuzione, cerca virgole extra!

In [92]:
stringa_farlocca = "ciao",   # OCCHIO
In [93]:
stringa_farlocca
Out[93]:
('ciao',)

Conversioni¶

Puoi creare una tupla da una qualsiasi sequenza, per esempio da una lista:

In [94]:
tuple( [8,2,5] )
Out[94]:
(8, 2, 5)
In [95]:
list( (3,4,2,3)  )   # viceversa
Out[95]:
[3, 4, 2, 3]

Tuple - operatori¶

I seguenti operatori funzionano sulle tuple e si comportano esattamente come per le liste:

Operatore Esempio Risultato Significato
lunghezza len(tuple) int Ritorna la lunghezza di una tupla
indice tuple[int] object Legge un elemento all'indice specificato
slice tuple[int:int] tuple Estrae una sotto-tupla - ritorna una NUOVA tupla
concatenazione tuple1 + tuple2 tuple Concatena due tuple - ritorna una NUOVA tupla
appartenenza object in tuple bool Controlla se un elemento è presente in una tupla
replicazione tuple * int tuple Replica la tupla - ritorna una NUOVA tupla
uguaglianza ==,!= bool Controlla se due tuple sono uguali o differenti

Riferimento: SoftPython - Tuple

Insiemi - set¶

Riferimenti: SoftPython, insiemi

Un insieme è una collezione mutabile senza ordine di elementi immutabili e distinti (cioè senza duplicati)

In [96]:
s = {'b','a','d','c'}
In [97]:
type(s)
Out[97]:
set
In [98]:
s = {'b','a','d','c'}
print(s)
{'d', 'a', 'b', 'c'}

ATTENZIONE: L'ORDINE NEGLI INSIEMI *NON* E' GARANTITO!

*NON* CREDERE A QUELLO CHE VEDI !!

L'ordine in cui è stata effettuata la stampa è diverso da quello con cui abbiamo costruito l'insieme - potrebbe anche variare a seconda della versione di Python.

Attenzione a cosa succede se proviamo a chiedere a Jupyter di mostrarci il contenuto dell'insieme, scrivendo solo la variabile s SENZA la print:

In [99]:
s
Out[99]:
{'a', 'b', 'c', 'd'}

Adesso appare in ordine alfabetico !

Motivo: Jupyter per mostrare le variabili invece della print normale stampa implicitamente con la pprint (pretty print), che SOLO per gli insiemi ci fa la cortesia di ordinare il risultato prima di stamparlo.

Rimuovere duplicati¶

Gli insiemi sono utili per rimuovere duplicati da una sequenza

Come per liste e stringhe, possiamo creare un set a partire da un'altra sequenza:

In [100]:
set('acacia') # da stringa
Out[100]:
{'a', 'c', 'i'}
In [101]:
set( [1,2,3,1,2,1,2,1,3,1] ) # da lista
Out[101]:
{1, 2, 3}

Indice degli elementi: con gli insiemi NON è possibile ricavare un elemento a partire da un indice:

s[0]

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-352-c9c96910e542> in <module>
----> 1 s[0]

TypeError: 'set' object is not subscriptable

Insieme vuoto¶

Per creare un insieme vuoto dobbiamo chiamare la funzione set():

In [102]:
s = set()

ATTENZIONE: Se scrivi {} otterrai un dizionario, NON un insieme !!!

Operatori insiemi¶

Operatore Esempio Risultato Descrizione
lunghezza len(set) int il numero di elementi nel set
appartenenza el in set bool verifica se elemento è contenuto nel set
unione set | set set crea un NUOVO set
intersezione set & set set crea un NUOVO set
differenza set - set set crea un NUOVO set
differenza simmetrica set ^ set set crea un NUOVO set
uguaglianza ==,!= bool Controlla se due insiemi sono uguali o differenti

Riferimento: SoftPython - Insiemi

Appartenenza¶

Per verificare se un elemento IMMUTABILE è contenuto in un insieme possiamo usare l'operatore in che ci ritorna un valore booleano:

In [103]:
'a' in {'m','e','n','t','a'}
Out[103]:
True

in NEGLI INSIEMI E' UN'OPERAZIONE MOLTO VELOCE

A differenza di liste e tuple, negli insiemi la velocità dell'operatore in NON dipende dalla dimensione della collezione

ATTENZIONE: Cercare elementi mutabili (es liste) in insiemi non è consentito:

['e','f'] in { ('c','d'), ('a','b')}

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_29295/1711245333.py in <module>
----> 1 ['a','b'] in { ('c','d'), ('a','b'), ('e','f') }

TypeError: unhashable type: 'list'
In [104]:
('e','f') in { ('c','d'), ('a','b') }   # una tupla invece è immutabile quindi possiamo cercarla
Out[104]:
False

Per verificare la non appartenza, ci sono due forme:

In [105]:
"carota" not in {"anguria","banana","mela"}
Out[105]:
True
In [106]:
not "carota" in {"anguria", "banana", "mela"}
Out[106]:
True

Insiemi - metodi simili agli operatori¶

Vi sono metodi analoghi agli operatori |, &, -, ^ che creano un NUOVO set.

NOTA: diversamente dagli operatori, questi metodi accettano come parametro una qualsiasi sequenza, non solo insiemi:

Metodo Risultato Descrizione Operatore analogo
set.union(seq) set unione, crea un NUOVO set |
set.intersection(seq) set intersezione, crea un NUOVO set &
set.difference(seq) set differenza, crea un NUOVO set -
set.symmetric_difference(seq) set differenza simmetrica, crea un NUOVO set ^

Metodi che MODIFICANO il primo insieme su cui sono chiamati (e ritornano None!):

Metodo Risultato Descrizione
setA.update(setB) None unione, MODIFICA setA
setA.intersection_update(setB) None intersezione, MODIFICA setA
setA.difference_update(setB) None differenza, MODIFICA setA
setA.symmetric_difference_update(setB) None differenza simmetrica, MODIFICA setA

Riferimenti: SoftPython - Insiemi

Dizionari - dict¶

I dizionari sono dei contenitori mutabili che consentono di abbinare dei valori a delle voci dette chiavi.

Riferimenti:

  • SoftPython - dizionari:
    1. introduzione
    2. operatori
    3. metodi

Dizionari - operatori¶

Operatore Esempio Ritorna Descrizione
lunghezza len(dict) int Ritorna il numero di chiavi
indice dict[chiave] obj Ritorna il valore associato alla chiave
modifica dict[chiave] = valore Aggiunge o modifica il valore associato ad una chiave
rimozione del dict[chiave] Rimuove la coppia chiave/valore
appartenenza chiave in dict bool Ritorna True se chiave è presente nel dizionario
uguaglianza ==,!= bool Controlla se due dizionari sono uguali o differenti

Riferimenti: SoftPython - Dizionari 2

Possiamo creare un dizionario con

  • graffe esterne { }
  • separando le chiavi dai valori con i due punti :
  • separando le coppie chiave/valore con la virgola ,
In [107]:
d = { 'sedia'   : 'un mobile per sedersi',
      'armadio' : 'un mobile a ripiani',                                                
}

Nota:

  • spazi / ritorni a capo non contano
  • l'ultima virgola è opzionale

Leggere valori¶

Per accedere ai valori, possiamo usare le chiavi tra parentesi quadre:

In [108]:
d = { 'sedia'   : 'un mobile per sedersi',
      'armadio' : 'un mobile a ripiani',                                                
}


d['sedia']
Out[108]:
'un mobile per sedersi'
In [109]:
d['armadio']
Out[109]:
'un mobile a ripiani'

Modificare associazioni¶

Possiamo aggiungere un'associazione così:

In [110]:
d['lampadario'] = 'un apparecchio di illuminazione'
In [111]:
d
Out[111]:
{'sedia': 'un mobile per sedersi',
 'armadio': 'un mobile a ripiani',
 'lampadario': 'un apparecchio di illuminazione'}

si può anche usare sovrascrivere le precedenti:

In [112]:
d['armadio'] = 'un mobile a ripiani, solitamente due ante'
In [113]:
d
Out[113]:
{'sedia': 'un mobile per sedersi',
 'armadio': 'un mobile a ripiani, solitamente due ante',
 'lampadario': 'un apparecchio di illuminazione'}

Dizionari - valori¶

Come valori nei dizionari possiamo mettere quello che ci pare, numeri, stringhe, tuple, liste, altri dizionari ..

In [114]:
ingredienti = { 'farina' : 500,
                'uova' : 2,
                'zucchero' : 200,
}
In [115]:
satelliti = {    
    'Marte'    : ['Phobos','Deimos'],
    'Saturno'  : ['Titano','Hyperion', 'Mimas', 'Enceladus', 'Dione','Rhea'],    
}

Dizionari - chiavi¶

  • possono essere solo tipi *immutabili*, come per es. numeri, stringhe, tuple:
  • non possono esserci chiavi duplicate
In [116]:
d = {}

d[123] = 'ammissibile'
d['una stringa'] = 'ok'
d[ ('oppure','una','tupla') ] =  'va bene'
In [117]:
d
Out[117]:
{123: 'ammissibile',
 'una stringa': 'ok',
 ('oppure', 'una', 'tupla'): 'va bene'}

Cosa succede se tentiamo di usare tipi mutabili?

d[ ['io', 'sono', 'una', 'lista'] ] = "OCCHIO!"

TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_3047/3187326270.py in <module>
----> 1 d[ ['io', 'sono', 'una', 'lista'] ] = "OCCHIO!"

TypeError: unhashable type: 'list'

Dizionari - operatore in¶

Per sapere se una chiave è contenuta in un dizionario, possiamo usare l'operatore in.

ATTENZIONE: in nei dizionari cerca solo nelle chiavi!

In [118]:
ingredienti = { 'farina'   : 500,
                'uova'     : 2,
                'zucchero' : 200,
}

'farina' in ingredienti
Out[118]:
True
In [119]:
500 in ingredienti
Out[119]:
False

Dizionari - Metodi¶

Metodo Ritorna Descrizione
dict.keys() dict_keys Ritorna una vista di chiavi che sono presenti nel dizionario
dict.values() dict_values Ritorna una vista di valori presenti nel dizionario
dict.items() dict_items Ritorna una vista di coppie (chiave, valore) presenti nel dizionario
d1.update(d2) None MODIFICA il dizionario diz1 con le coppie chiave / valore trovate in diz2

ATTENZIONE: i metodi keys, values e items restituiscono viste immutabili e sono spesso causa di fraintendimenti e/o codice inefficiente. Se ti senti nella necessità di usarli, chiediti sempre se è possibile risolvere il problema usando solo gli operatori.

Riferimenti: SoftPython - dizionari 3

Copy vs deep copy¶

Se vogliamo copiare una struttura dati mutabili, abbiamo a disposizione il metodo .copy()

  • .copy effettua solo una cosiddetta copia in superficie (shallow copy)

  • per la copia in profondità (deep copy) servono altri sistemi!

Esempio - lista di liste¶

In [120]:
listonaA = [ ['Fate', 'attenzione'], 
             ['a', 'dove'],
             ['puntano', 'le', 'frecce']
]
print(listonaA)
[['Fate', 'attenzione'], ['a', 'dove'], ['puntano', 'le', 'frecce']]

Proviamo a visualizzare il codice in Python Tutor:

immagine-3.png

Proviamo adesso a fare una copia con il metodo .copy():

In [121]:
listonaA = [ ['Fate', 'attenzione'], 
             ['a', 'dove'],
             ['puntano', 'le', 'frecce']
]
listonaB = listonaA.copy()  # copia *in superficie*
print(listonaA)
print(listonaB)
[['Fate', 'attenzione'], ['a', 'dove'], ['puntano', 'le', 'frecce']]
[['Fate', 'attenzione'], ['a', 'dove'], ['puntano', 'le', 'frecce']]

immagine-2.png

Notiamo che abbiamo due listone le cui celle puntano a delle sottoliste condivise, quindi scrivendo in una sotto cella di listonaA di fatto finiamo anche per scrivere in listonaB!

In [122]:
listonaA = [ ['Fate', 'attenzione'], 
             ['a', 'dove'],
             ['puntano', 'le', 'frecce']
]

listonaB = listonaA.copy()  # copia *in superficie*

listonaA[2][0]  = 'OCCHIO!' # cella con 'frecce'

print(listonaA)
print(listonaB)
[['Fate', 'attenzione'], ['a', 'dove'], ['OCCHIO!', 'le', 'frecce']]
[['Fate', 'attenzione'], ['a', 'dove'], ['OCCHIO!', 'le', 'frecce']]

immagine.png

Per rimediare possiamo usare la cosidetta copia in profondità (deep copy) prima importando il modulo copy e poi chiamando la sua funzione deepcopy e passandogli come parametro listonaA:

In [123]:
import copy   # MODULO PYTHON

listonaA = [ ['Fate', 'attenzione'], 
             ['a', 'dove'],
             ['puntano', 'le', 'frecce']
]

listonaB = copy.deepcopy(listonaA)

listonaA[2][0]  = 'OCCHIO!' # cella con 'frecce'

print(listonaA)
print(listonaB)
[['Fate', 'attenzione'], ['a', 'dove'], ['OCCHIO!', 'le', 'frecce']]
[['Fate', 'attenzione'], ['a', 'dove'], ['puntano', 'le', 'frecce']]

Con copy.deepcopy abbiamo veramente strutture dati completamente distinte:

immagine-2.png

Esercizi rapidi¶

  • (solo sul notebook)

Sfide¶

Sfida - Censura al tiramisù¶

✪ Ci è stato inviato un testo illegale, immorale e che fa pure ingrassare. Per tutelare la pubblica salute abbiamo l'arduo compito di censurarlo e renderlo consono al buon costume.

  1. E' necessario sostituire OGNI occorrenza di due parole_malefiche con una più salubre censura, trasformando il testo in modo che la print di testo_censurato non contenga nessuna parola incriminata.

Esempio:

testo= "Grazie all'uso di Cera Splendent tutto brilla!"
parola_malefica = "splendent"
censura = "******"
testo_censurato: "Grazie all'uso di Cera ****** tutto brilla!"
  1. Per scrivere il nostro rapporto di censori dobbiamo rendere conto di quante parole abbiamo censurato. Stampare alla fine il numero (ovviamente in maniera automatica ), per esempio:
"Censurata 1 parola"
In [136]:
testo = """Ed è proprio da questa portentosa crema che nasce la crema 
al mascarpone base del tiramisù, prima classificata al premio Crema 
dell'Anno insieme alla nutella. Il dolce italiano per eccellenza, 
quello più famoso e amato, ma soprattutto che ha dato vita a 
tantissime altre versioni, anche tiramisù senza uova! Poi il Tiramisù
alle fragole o quello alla Nutella, giusto per citarne un paio!
Senza contare le rivisitazioni più raffinate come la crostata morbida
o la torta al tiramisù.
"""

parola_malefica1 = "Tiramisù"
parola_malefica2 = "nutella"

censura = "******"

testo_censurato = ''

# scrivi qui

Sfida - Cantina¶

✪✪ Requisiti: liste

Data una stringa parola, creare una NUOVA lista che contenga la parola seguita da sè stessa rovesciata

  • NOTA: l'ultima lettera NON deve essere duplicata

Esempio - dato:

parola = "cantina"

deve stampare:

['c', 'a', 'n', 't', 'i', 'n', 'a', 'n', 'i', 't', 'n', 'a', 'c']
In [139]:
parola = "cantina" #['c','a','n','t','i','n','a','n','i','t','n','a','c']
#parola = "vino"   # ['v', 'i', 'n', 'o', 'n', 'i', 'v']
#parola = "ok"     # ['o', 'k', 'o']

# scrivi qui

Sfida - Nozze di platino¶

✪ Requisiti: dizionari

Al tranquillissimo paesino di Gerontonia vi sono delle coppie assai tenaci che dopo 75 anni dal fatico "Sì!" meritano di festeggiare le nozze di platino. Abbiamo una lista dei matrimoni con esattamente 3 coppie scritte nel formato "maschio-femmina", e vogliamo creare un dizionario diz che associa ad ogni maschio la corrispondente compagna.

  • assumi che i nomi dei maschi siano tutti diversi e che vi siano esattamente 3 coppie

Esempio - data:

matrimoni = ["Amilcare-Maria Eusonia", "Oronzo Pio-Genoveffa", "Venceslao-Elvira"]

dopo il tuo codice, deve risultare:

>>> print(diz)
{'Amilcare'   : 'Maria Eusonia',
 'Oronzo Pio' : 'Genoveffa',
 'Venceslao'  : 'Elvira'}
In [141]:
matrimoni = ["Amilcare-Maria Eusonia", "Oronzo Pio-Genoveffa", "Venceslao-Elvira"]
#matrimoni = ["Liutprando-Brunilde", "Clodoveo-Elvira Pancrazia Ludmilla", 
             # "Gian Evaristo-Ubalda"]

# scrivi qui
In [ ]: