Introduzione rapida a Python

Scarica zip esercizi

Naviga file online

REQUISITI:

  • QUESTO FOGLIO E’ PER CHI HA GIA’ COMPETENZE DI PROGRAMMAZIONE, e in 3-4h vuole farsi rapidamente un’idea di Python

  • Aver installati Python 3 e Jupyter: se non hai già provveduto, guarda Installazione

SE SEI UN PRINCIPIANTE: Salta questo foglio e fai invece i tutorial che trovi nella sezione Fondamenti, a partire da Strumenti e script

Che fare

  • scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere:

Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.

quick-intro
    quick-intro.ipynb
    quick-intro-sol.ipynb
    jupman.py

ATTENZIONE: In questo libro 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

  • apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook quick-intro.ipynb

  • 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. Gli esercizi sono graduati per difficoltà, da una stellina ✪ a quattro ✪✪✪✪

Ricordati di eseguire sempre la prima cella dentro il notebook.

Contiene delle istruzioni come import jupman che dicono a Python quali moduli servono e dove trovarli. Per eseguirla, vedi le seguenti scorciatoie

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

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:

[2]:
# 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
[3]:
# scrivi qui


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.

Principali tipi di dati Python

Dato che il tema del libro è il trattamento dei dati, per cominciare ci focalizzeremo sui tipi di dati in Python.

Riferimenti:

Quando leggiamo delle informazioni da una fonte esterna come un file, poi dovremo inevitabilmente incastonare i dati letti in qualche combinazione di questi tipi:

Tipo

Esempio 1

Esempio 2

Esempio 3

int

0

3

-5

float (numero in virgola mobile)

0.0

3.7

-2.3

bool

False

True

str

""

"Buon giorno"

'come stai?'

list

[]

[5, 8, 10]

``[“qualcosa”, 5, “altro ancora”]` `

dict

{}

{'chiave 1':'valore 1', ' chiave 2':'valore 2'}

{5:'un valore stringa', 'chiave stringa':7}

A volte, useremo tipi più complessi, per esempio i valori temporali si potrebbero mettere in oggetti di tipo datetime che oltre alla data vera e propria possono contenere anche il fuso orario.

In quel che segue, forniremo alcuni esempi rapidi su quello che si può fare sui vari tipi di dato, mettendo riferimenti a spiegazioni più dettagliate nel resto del libro.

Numeri interi e con virgola

Mettiamo qua due note velocissime:

Riferimenti:

In Python abbiamo numeri interi:

[4]:
3 + 5
[4]:
8

La somma tra interi ovviamente ci da un intero:

[5]:
type(8)
[5]:
int

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

[6]:
3 / 4
[6]:
0.75
[7]:
type(0.75)
[7]:
float

ATTENZIONE al punto !

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

✪ ESERCIZIO: Prova a scrivere qua sotto 3.14 con il punto, e poi 3,14 con la virgola ed esegui con Ctrl+Invio. Cosa appare nei due casi?

[8]:
# scrivi qui con il punto


[9]:
# scrivi qui con la virgola


✪ ESERCIZIO: Prova a scrivere qua sotto 3 + 1.0 ed esegui con Ctrl+Invio. Di quale tipo sarà il risultato? Controlla anche usando il comando type.

[10]:
# scrivi qui i comandi

✪ ESERCIZIO: Qualche professore di matematica ti avrà sicuramente intimato di non dividere mai per zero. Neanche a Python piace molto, prova a scrivere nella cella qua sotto 1 / 0 e poi premi Ctrl+Invio per eseguire la cella. Nota come Python riporterà la riga dove è accaduto l’errore:

[11]:
# scrivi qui sotto il codice

Booleani - bool

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

Riferimenti

Per indicare i booleani Python ci fornisce due costanti True e False. Cosa ci possiamo fare?

Operatore and

Potremmo usarle per segnare in variabili se un certo fatto è avvenuto, per esempio possiamo fare un programma che al mattino ci dice che possiamo uscire di casa solo dopo aver fatto entrambe (and) colazione e lavato i denti:

[12]:
fatto_colazione = True
lavato_denti = True

if fatto_colazione and lavato_denti:
    print("fatto tutto !")
    print("posso uscire di casa")
else:
    print("NON posso uscire di casa")

fatto tutto !
posso uscire di casa

✪ ESERCIZIO: prova a scrivere qui sotto a mano il programma riportato nella cella precedente, ed eseguilo con Control+Invio. Prova a cambiare i valori da True a False e guarda che succede.

Assicurati di provare tutti i casi:

  • True True

  • True False

  • False True

  • False False

ATTENZIONE: Ricordati i : alla fine della riga con if !!!!

[13]:
# scrivi qui


Si può anche mettere un if dentro l’altro (nested if). Per esempio, questo programma qui funziona esattamente come il precedente:

[14]:
fatto_colazione = True
lavato_denti = True

if fatto_colazione:
    if lavato_denti:                        # NOTA: Questo blocco if è indentato rispetto
        print("fatto tutto !")              #       all' if fatto_colazione
        print("posso uscire di casa!")      #
    else:
        print("NON posso uscire di casa")
else:
    print("NON posso uscire di casa")
fatto tutto !
posso uscire di casa!

✪ ESERCIZIO: Prova a modificare il programma riportato nella cella precedente per fargli riportare lo stato delle varie azioni compiute. Elenchiamo qui i possibili casi e i risultati attesi:

  • True False

ho fatto colazione
non ho lavato i denti
NON posso uscire di casa
  • False True

  • False False

non ho fatto colazione
NON posso uscire di casa
  • True True

    ho fatto colazione
    ho lavato i denti
    fatto tutto !
    posso uscire di casa!
    
Mostra soluzione
[15]:

# scrivi qui

Operatore or

Per verificare se almeno di due condizioni si è verificata, si usa or. Per esempio, possiamo stabilire che per fare colazione ci serve avere del latte intero o scremato (nota: se li abbiamo tutte e due riusciamo a fare colazione lo stesso !)

[16]:
ho_latte_intero = True
ho_latte_scremato = False

if ho_latte_intero or ho_latte_scremato:
    print("posso fare colazione !")
else:
    print("NON posso fare colazione :-(")
posso fare colazione !

✪ ESERCIZIO: prova a scrivere qui sotto a mano il programma riportato nella cella presedente, ed eseguilo con Control+Invio. Prova a cambiare i valori da True a False e guarda che succede:

Assicurati di provare tutti i casi:

  • True True

  • True False

  • False True

  • False False

[17]:
# scrivi qui


✪✪ ESERCIZIO: prova a fare un programma che ti dice se puoi uscire di casa solo se hai fatto colazione (per cui devi avere hai almeno un tipo di latte) e lavato i denti

Mostra soluzione
[18]:
ho_latte_intero = False
ho_latte_scremato = True
lavato_denti = False


# scrivi qui


posso fare colazione !
NON posso uscire di casa

Operatore not

Per le negazioni, puoi usare il not:

[19]:
not True
[19]:
False
[20]:
not False
[20]:
True
[21]:
fatto_colazione = False

if not fatto_colazione:
    print("Ho fame !")
else:
    print("che buoni che erano i cereali")
Ho fame !
[22]:
fatto_colazione = True

if not fatto_colazione:
    print("Ho fame !")
else:
    print("che buoni che erano i cereali")
che buoni che erano i cereali

✪✪ ESERCIZIO: prova a fare un programma che ti dice se puoi nuotare se NON hai fatto colazione E hai il salvagente

Assicurati di provare tutti i casi:

  • True True

  • True False

  • False True

  • False False

Mostra soluzione
[23]:

hai_salvagente = True fatto_colazione = True # scrivi qui

NON puoi nuotare

Non solo True e False

ATTENZIONE ai booleani diversi da True e False !

In Python, il numero 0 e altri oggetti ‘nulli’ (come l’oggetto None, la stringa vuota "" e la lista vuota []) sono considerati False, e tutto ciò che non è ‘nullo’ è considerato True!

Facciamo degli esempi per mostrare quanto sopra riportato:

[24]:
if True:
    print("questo")
    print("sarà")
    print("stampato")
else:
    print("quest'altro")
    print("non sarà stampato")
questo
sarà
stampato

Tutto ciò che non è ‘nullo’ è considerato True, verifichiamolo per esempio con la stringa "ciao":

[25]:
if "ciao":
    print("anche questo")
    print("sarà stampato!!")
else:
    print("e questo no")
anche questo
sarà stampato!!
[26]:
if False:
    print("io non sarò stampato")
else:
    print("io sì")
io sì
[27]:
if 0:
    print("anche questo non sarà stampato")
else:
    print("io sì")
io sì
[28]:
if None:
    print("neppure questo sarà stampato")
else:
    print("io sì")
io sì
[29]:
if "":  # stringa vuota
    print("Neanche questo sarà stampato !!!")
else:
    print("io sì")
io sì

✪ ESERCIZIO: Copia qua sotto l’if una stringa con uno spazio dentro " " nella condizione dell’if. Cosa succederà?

  • prova anche a mettere una lista vuota [], che succede?

Mostra soluzione
[30]:

# scrivi qui l'if

Stringhe - str

Le stringhe sono sequenze immutabili di caratteri.

Riferimenti:

SoftPython:

Concatenare stringhe

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

[31]:
"ciao " + "mondo"
[31]:
'ciao mondo'

Ma nota che quando concateniamo una stringa e un numero, Python si arrabbia:

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

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

Questo succede perchè Python vuole che convertiamo esplicitamente il numero ‘5’ in una stringa. Porrà simili lamentela anche con altri tipi di oggetti. Quindi, quando concatenate oggetti che non sono stringhe, per evitare problemi racchiudete l’oggetto da convertire nella funzione str come qui:

[32]:
"ciao " + str(7)
[32]:
'ciao 7'

Un modo alternativo e più veloce è usare l’operatore di formattazione percentuale %, che sostituisce alle occorrenze di %s quello che mettete dopo un % dopo la stringa :

[33]:
"ciao %s" % 7
[33]:
'ciao 7'

Meglio ancora, il %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") (una tupla è semplicemente una sequenza immutabile di elementi racchiusi tra parentesi tonde e separati da virgole)

[34]:
"Che %s finalmente imparo %s" % ("bello", "Python")
[34]:
'Che bello finalmente imparo Python'

✪ ESERCIZIO: il %s funziona con le stringhe ma anche con quasiasi altro tipo di dato, per esempio un intero. Scrivi qua sotto il comando sopra, aggiunendo un %s alla fine della stringa, e aggiungendo alla fine della tupla il numero 3 (separandolo dagli altri con una virgola).

Domanda: i %s possono stare uno dopo l’altro senza spazi tra di loro? Prova.

[35]:
# scrivi qui


Usare metodi degli oggetti

Quasi tutto in Python è un oggetto, faremo qui una velocissima introduzione tanto per dare l’idea.

Riferimenti

Quasi tutto in Python è un oggetto. Per esempio, le stringhe sono oggetti. Ogni tipo di oggetto ha delle azioni chiamati metodi che si possono eseguire su quello oggetto. Per esempio, per le stringhe che rappresentano nomi potremmo voler rendere in maiuscolo la prima lettera: a tal fine possiamo cercare se per le stringhe ci sono giò metodi esistenti che fanno questo. Proviamo il metodo esistente capitalize() sulla stringa "trento" (notare che la stringa è tutta in minuscolo e capital in inglese vuol anche dire ‘maiuscolo’ ):

[36]:

"trento".capitalize()
[36]:
'Trento'

Python ci ha appena fatto la cortesia di rendere la prima lettera della parola in maiuscolo 'Trento'

✪ ESERCIZIO: Scrivi nella cella qua sotto "trento". e premi TAB: Jupyter dovrebbe suggerirti dei metodi disponibili per la stringa. Prova il metodo upper() e count("t")

[37]:
# scrivi qui


Liste - list

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

Riferimenti - SoftPython:

Creiamo una lista di stringhe:

[38]:
x = ["ciao", "soft", "python"]
[39]:
x
[39]:
['ciao', 'soft', 'python']

Le liste sono sequenze di oggetti possibilmente eterogenei, quindi dentro ci potete buttare di tutto, interi, stringhe, dizionari …:

[40]:
x = ["ciao", 123, {"a":"b"}]
[41]:
x
[41]:
['ciao', 123, {'a': 'b'}]

Per accedere ad un elemento in particolare dentro una lista, si può usare un indice tra parentesi quadre che indica un elemento:

[42]:
# primo elemento

x[0]
[42]:
'ciao'
[43]:
# secondo elemento

x[1]
[43]:
123
[44]:
# terzo elemento

x[2]
[44]:
{'a': 'b'}

In una lista possiamo cambiare gli elementi con l’assegnazione:

[45]:
# Cambiamo il *secondo* elemento:

x[1] = "soft"
[46]:
x
[46]:
['ciao', 'soft', {'a': 'b'}]
[47]:
x[2] = "python"
[48]:
x
[48]:
['ciao', 'soft', 'python']

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

[49]:
x = ["ciao", "soft", "python"]

len(x)
[49]:
3

✪ ESERCIZIO: prova ad accedere ad un elemento fuori dalla lista, e vedi che succede.

  • x[3] è dentro o fuori dalla lista?

  • C’è una qualche lista x per cui possiamo scrivere x[len(x)] senza problemi ?

  • se usi indici negativi, che succede? Prova -1, -2, -3, -4 …

[50]:
# scrivi qui


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

[51]:

x = []
[52]:
x
[52]:
[]
[53]:
x.append("ciao")
[54]:
x
[54]:
['ciao']
[55]:
x.append("soft")
[56]:
x
[56]:
['ciao', 'soft']
[57]:
x.append("python")
[58]:
x
[58]:
['ciao', 'soft', 'python']

Ordinamento liste

Le liste possono ordinare comodamente con il metodo .sort, che funziona su tutti gli oggetti ordinabili. Per esempio, possiamo ordinare i numeri:

IMPORTANTE: .sort() modifica la lista su cui è chiamato, non ne genera una nuova !

[59]:
x = [ 8, 2, 4]

x.sort()
[60]:
x
[60]:
[2, 4, 8]

Come altro esempio, possiamo ordinare le stringhe:

[61]:
x = [ 'mondo', 'python',  'ciao',]

x.sort()
x
[61]:
['ciao', 'mondo', 'python']

Se non volessimo modificare la lista originale e invece volessimo generarne una nuova, useremmo la funzione sorted(). NOTA: sorted è una funzione, non un metodo:

[62]:
x = [ 'mondo', 'python', 'ciao',]

sorted(x)
[62]:
['ciao', 'mondo', 'python']
[63]:
# l'x originale non è cambiato:
x
[63]:
['mondo', 'python', 'ciao']

✪ ESERCIZIO: Che succede se ordini stringhe contenenti gli stessi caratteri ma maiscoli invece di minuscoli? Come vengono ordinati? Fai delle prove.

[64]:
# scrivi qui

✪ ESERCIZIO: Che succede se nella stessa lista metti sia stringhe che numeri e provi ad ordinarla? Fai delle prove.

[65]:
# scrivi qui

Ordine rovesciato

Supponiamo di voler ordinare la lista alla rovescia usando sorted. Per fare cioò possiamo indicare a Python il parametro booleano reverse e il suo valore, che in questo caso sarà True. Questo ci permette di notare come Python consenta di usare parametri opzionali specificandoli per nome :

[66]:
sorted(['mondo', 'python', 'ciao'], reverse=True)
[66]:
['python', 'mondo', 'ciao']

✪ ESERCIZIO: Per cercare informazioni su sorted, avremmo potuto chiedere a Python dell’aiuto. Per fare ciò Python mette a disposizione una comoda funzione chiamata help, che potresti usare così help(sorted). Prova ad eseguirla nella cella qua sotto. A volte l’help è piuttosto complesso, e sta a noi sforzarci un po’ per individuare i parametri di interesse

[67]:
# scrivi qui



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 un po’ nella libreria di Python, vediamo che c’è una comoda funzione reversed() che prende come paramatro la lista che vogliamo rovesciare e ne genera una nuova rovesciata.

✪ ESERCIZIO: Prova ad eseguire reversed([6,2,4]) nella cella qua sotto, e guarda che output ottieni. E’ quello che ti aspetti ? In genere, e specialmente in Python 3, quando ci aspettiamo una lista e per caso vediamo invece un oggetto col nome iterator, possiamo risolvere passando il risultato come parametro della funzione list()

[68]:
# scrivi qui il codice


Dizionari - dict

I dizionari sono dei contenitori che ci consentono di abbinare dei valori a delle voci dette chiavi. Qua faremo un esempio rapidissimo per dare un’idea.

Riferimenti:

Possiamo creare un dizionario con le graffe { }, separando le chiavi dai valori con i due punti :, e separando le coppie chiave/valore con la virgola ,:

[69]:
d = {  'chiave 1':'valore 1',
       'chiave 2':'valore 2' }

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

[70]:
d['chiave 1']
[70]:
'valore 1'
[71]:
d['chiave 2']
[71]:
'valore 2'

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

[72]:
d['chiave 3'] = 123
[73]:
d
[73]:
{'chiave 1': 'valore 1', 'chiave 2': 'valore 2', 'chiave 3': 123}
[74]:
d['chiave 4'] = ('io','sono', 'una', 'tupla')
[75]:
d
[75]:
{'chiave 1': 'valore 1',
 'chiave 2': 'valore 2',
 'chiave 3': 123,
 'chiave 4': ('io', 'sono', 'una', 'tupla')}

✪ ESERCIZIO: prova ad inserire nel dizionario delle coppie chiave valore con chiavi stringa e come valori delle liste e altri dizionari,

[76]:
# scrivi qui:



Chiavi: Per le chiavi abbiamo delle restrizioni: possono essere solo tipi immutabili. Abbiamo già usato le stringhe quindi sappiamo che sono immutabili. Anche i numeri sono immutabili:

[77]:
d[123] = 'valore 3'
[78]:
d
[78]:
{'chiave 1': 'valore 1',
 'chiave 2': 'valore 2',
 'chiave 3': 123,
 'chiave 4': ('io', 'sono', 'una', 'tupla'),
 123: 'valore 3'}

Le tuple sono sequenze immutabili perciò possiamo usarle come chiavi:

[79]:
d[('io','sono','una','tupla')] = 'valore 4'
[80]:
d
[80]:
{'chiave 1': 'valore 1',
 'chiave 2': 'valore 2',
 'chiave 3': 123,
 'chiave 4': ('io', 'sono', 'una', 'tupla'),
 123: 'valore 3',
 ('io', 'sono', 'una', 'tupla'): 'valore 4'}

ATTENZIONE: Non tutti i tipi vanno bene a Python come chiavi. Senza andare nei dettagli, in genere non puoi inserire nei dizionari dei tipi che possono essere modificati dopo che sono stati creati.

✪ ESERCIZIO:

  • Prova ad inserire in un dizionario una lista tipo ['a','b']come chiave, e come valore metti quello che vuoi. Python non dovrebbe permetterti di farlo, e ti dovrebbe mostrare la scritta TypeError: unhashable type: 'list'

  • prova anche ad inserire un dizionario come chiave (per es. anche il dizionario vuoto {}). Che risultato ottieni?

Visualizzare l’esecuzione con Python Tutor

Abbiamo visto i principali tipi di dati. Prima di procedere oltre, è bene vedere gli strumenti giusti per comprendere al meglio cosa succede quando si esegue il codice. Python tutor è un ottimo sito online per visualizzare online l’esecuzione di codice Python, permettendo di andare avanti e indietro nell’esecuzione del codice. Sfruttatelo più che potete, dovrebbe funzionare con parecchi degli esempi che tratteremo nel libro. Vediamo un esempio.

Python tutor 1/4

Vai sul sito pythontutor.com e seleziona Python 3

pytut-1-8231

Python tutor 2/4

pytut-2-498273

Python tutor 3/4

pytut-3-89142

Python tutor 4/4

pytut-4-27854

Debuggare codice in Jupyter

Python tutor è fantastico, ma quando esegui del codice in Jupyter e non funziona, come si può fare? Per ispezionare l’esecuzione, gli editor di solito mettono a disposizione uno strumento chiamato debugger, che permette di eseguire le istruzioni una per una. Al momento (Agosto 2018), il debugger di Jupyter che si chiama pdb è estremamente limitato . Per superarne le limitazioni, in questo libro ci siamo inventati una soluzione di ripiego, che sfrutta Python Tutor.

Se inserisci del codice Python in una cella, e poi alla fine della cella scrivi l’istruzione jupman.pytut(), come per magia il codice precedente verrà visualizzato all’interno del foglio Jupyter con il debugger di Python Tutor.

ATTENZIONE: jupman è una collezione di funzioni di supporto che ci siamo inventati apposta per questo libro.

Quando vedi comandi che iniziano con jupman, affinchè funzionino devi prima eseguire la cella in cima al documento. Riportiamo tale cella qua per comodità. Se non lo hai già fatto, eseguila adesso.

[81]:
# Ricordati di eseguire questa cella con Control+Invio
# Questi comandi dicono a Python dove trovare il file jupman.py
import jupman;

Adesso siamo pronti a provare Python tutor con la funzione magica jupman.pytut():

[82]:
x = 5
y = 7
z = x + y

jupman.pytut()
[82]:
Python Tutor visualization

Python Tutor : Limitazione 1

Python tutor è comodo, ma ci sono importanti limitazioni:

ATTENZIONE: Python Tutor guarda dentro una cella sola!

Quando usi Python tutor dentro Jupyter, l’unico codice che viene considerato da Python tutor è quello dentro la cella dove sta il comando jupman.pytut().

Quindi per esempio in queste due celle che seguono, solo print(w) apparirà dentro Python tutor senza il w = 3. Se proverai a cliccare Forward in Python tutor, ti verrà segnalato che non è stata definita w

[83]:
w = 3
[84]:
print(w)

jupman.pytut()
3
Traceback (most recent call last):
  File "../jupman.py", line 2453, in _runscript
    self.run(script_str, user_globals, user_globals)
  File "/usr/lib/python3.7/bdb.py", line 578, in run
    exec(cmd, globals, locals)
  File "<string>", line 2, in <module>
NameError: name 'w' is not defined
[84]:
Python Tutor visualization

Per avere tutto in Python tutor devi mettere tutto il codice nella stessa cella:

[85]:
w = 3
print(w)

jupman.pytut()
3
[85]:
Python Tutor visualization

Python Tutor : Limitazione 2

Un’altra limitazione è la seguente:

ATTENZIONE: Python tutor usa solo funzioni dalla distribuzione standard di Python**

Python Tutor va bene per ispezionare semplici algoritmi che usano funzioni di base di Python.

Se usate qualche libreria tipo numpy, potete provare solo online a selezionare Python 3.6 with anaconda

pytut-5-781302

Iterazione

Spesso è utile compiere azioni su ogni elemento di una sequenza.

Riferimenti

Cicli for

Tra i vari modi per farlo, uno è usare i cicli for

[86]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for animale in animali:
    print("Nella lista ci sono:")
    print(animale)
Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli
Nella lista ci sono:
alci

Qua abbiamo definito la variabile animale (avremmo potuto chiamarla con qualunque nome, anche pippo). Per ogni elemento nella lista animali, vengono eseguite le istruzioni dentro il blocco. Ogni volta che le istruzioni vengono eseguite, la variabile animale assume uno dei valori della lista animali

ATTENZIONE 1: RICORDATI I DUE PUNTI : ALLA FINE DELLA LINEA DEL FOR !!!

ATTENZIONE 2: Per indentare il codice, usa SEMPRE sequenze di 4 spazi bianchi.

Sequenze di 2 soli spazi per quanto consentite non sono raccomandate.

ATTENZIONE 3: Il comportamento di TAB dipende dal tuo editor.

A seconda dell’editor che usi, premendo TAB potresti ottenere una sequenza di spazi bianchi come accade in Jupyter (4 spazi che sono raccomandati), oppure un carattere speciale di tabulazione (da evitare)! Per quanto noiosa questa distinzione ti possa apparire, ricordatela perchè potrebbe generare errori molto difficili da scoprire.

[87]:
# Guardiamo cosa succede con Python tutor:

animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for animale in animali:
    print("Nella lista ci sono:")
    print(animale)

jupman.pytut()
Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli
Nella lista ci sono:
alci
[87]:
Python Tutor visualization

✪ ESERCIZIO: Proviamo a capire meglio tutti gli Attenzione qua sopra. Scrivi qui sotto il for con gli animali di prima (niente copia e incolla!), vedi se funziona. Ricordati di usare 4 spazi per le indentazioni.

  • Poi prova a togliere i due punti alla fine e vedi che errore ti da Python

  • Riaggiungi i due punti, e adesso prova a variare l’indentazione. Prova a mettere due spazi all’inizio di entrambi i print, vedi se esegue

  • Adesso prova a mettere due spazi prima del primo print e 4 spazi prima del secondo, e vedi se esegue

[88]:
# scrivi qui - copia il for di sopra

for in range

Un’altra iterazione molto comune è incrementare un contatore ad ogni ciclo. Python rispetto ad altri linguaggi offre un sistema piuttosto particolare che usa la funzione range(n), che ritorna una sequenza con i primi numeri da 0 incluso a n escluso. La possiamo usare così:

[89]:
for indice in range(3):
    print(indice)
0
1
2
[90]:
for indice in range(6):
    print(indice)
0
1
2
3
4
5

Guardiamo meglio con Python tutor:

[91]:
for indice in range(6):
    print(indice)

jupman.pytut()
0
1
2
3
4
5
[91]:
Python Tutor visualization

Quindi possiamo usare questo stile come un’alternativa per listare i nostri animali:

[92]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for indice in range(3):
    print("Nella lista ci sono:")
    print(animali[indice])
Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli

Guardiamo meglio con Python tutor:

[93]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for indice in range(3):
    print("Nella lista ci sono:")
    print(animali[indice])

jupman.pytut()
Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli
[93]:
Python Tutor visualization

Funzioni

Una funzione prende dei parametri e li usa per produrre o riportare qualche risultato.

Riferimenti

Per definire una funzione, possiamo usare la parola chiave def:

[94]:
def mia_stampa(x,y):   # RICORDATI I DUE PUNTI ':' ALLA FINE DELLA RIGA !!!!!
    print('Ora stamperemo la somma di due numeri')
    print('La somma è %s' % (x + y))

Possiamo chiamare la funzione così:

[95]:
mia_stampa(3,5)
Ora stamperemo la somma di due numeri
La somma è 8

Vediamo meglio che succede con Python Tutor:

[96]:
def mia_stampa(x,y):    # RICORDATI I DUE PUNTI ':' ALLA FINE DELLA RIGA !!!!!
    print('Ora stamperemo la somma di due numeri')
    print('La somma è %s' % (x + y))

mia_stampa(3,5)

jupman.pytut()
Ora stamperemo la somma di due numeri
La somma è 8
[96]:
Python Tutor visualization

La funzione appena dichiarata stampa dei valori, ma non ritorna nulla. Per fare una funzione che ritorni un valore, dobbiamo usare la parola chiava return

Trovi questo tipo di funzioni anche sul libro Pensare in Python, Capitolo 6, Funzioni produttive, di cui puoi fare tutto saltando la parte 6.5 sulla ricorsione. NOTA: nel libro viene usato il termine strano “funzioni produttive” per quelle funzioni che ritornano un valore, ed il termine ancora più strano “funzioni vuote” per funzioni che non ritornano nulla ma fanno qualche effetto tipo stampa a video: ignora questi strani termini !

[97]:
def mia_somma(x,y):
    s = x + y
    return s

[98]:
mia_somma(3,5)

[98]:
8
[99]:
# Vediamo meglio  che succede con Python Tutor:

def mia_somma(x,y):
    s = x + y
    return s

print(mia_somma(3,5))

jupman.pytut()
8
[99]:
Python Tutor visualization

✪ ESERCIZIO: Se proviamo ad assegnare ad una variabile x il valore di ritorno delle funzione mia_stampa che apparentemente non ritorna nulla, che valore ci sarà in x? Prova a capirlo qua sotto:

[100]:
# scrivi qui

✪ ESERCIZIO: Scrivi qua sotto una funzione media che calcola e ritorna la media tra due numeri x e y in input

Mostra soluzione
[101]:
# scrivi qui


✪✪ ESERCIZIO: Scrivi qua sotto una funzione che chiameremo iniziab che prende una stringa x in ingresso. Se la stringa inizia con la lettera 'b', per esempio 'bianco' la funzione stampa la scritta bianco inizia con b, altrimenti stampa che non inizia con la b.

  • Per controllare se il primo carattere è uguale alla 'b', usa l’operatore == (ATTENZIONE: è un DOPPIO uguale !)

  • Se la stringa è vuota la tua funzione può avere problemi? Come potresti risolverli? (Per separare più condizioni nell’if, usa l’operatore and oppure or a seconda di come hai costruito l’if).

Mostra soluzione
[102]:
# scrivi qui


bianco inizia con b
verde non inizia con b
 non inizia con b

Funzioni lambda

In Python una variabile può contenere una funzione. Per esempio, sappiamo che len("ciao") ci dà la lunghezza della stringa "ciao"

[103]:
len("ciao")
[103]:
4

Proviamo a creare una variabile mia_variabile che punta alla funzione len.

[104]:

mia_variabile = len

NOTA: non abbiamo aggiunto parametri a len!

Adesso possiamo usare mia_variabile esattamente come usiamo la funzione len, che da la lunghezza di sequenze come le stringhe

[105]:
mia_variabile("ciao")
[105]:
4

Possiamo anche riassegnare mia_variabile ad altre funzioni, per esempio sorted. Vediamo che succede:

[106]:
mia_variabile = sorted

chiamando mia_variabile, ci aspettiamo di vedere i caratteri di "ciao" in ordine alfabetico:

[107]:
mia_variabile("ciao")
[107]:
['a', 'c', 'i', 'o']

In Python possiamo definire funzioni in una sola riga, con le cosiddette funzioni lambda:

[108]:
mia_f = lambda x: x + 1

Cosa fa mia_f ? Prende un parametro x e ritorna il risultato di calcolare l’espressione x + 1:

[109]:
mia_f(5)
[109]:
6

Possiamo anche passare due parametri:

[110]:
mia_somma = lambda x,y: x + y
[111]:
mia_somma(3,5)
[111]:
8

✪ ESERCIZIO: Prova a definire qua sotto una funzione lambda per calcolare la media tra due numeri x e y, e assegnala alla variabile media

Mostra soluzione
[112]:

# scrivi qui

Trasformazioni sulle liste

Riferimenti:

Supponiamo di voler prendere la lista di animali e generarne una nuova in cui tutti i nomi iniziano con la lettera maiuscola. Questa che vogliamo fare di fatto è la creazione di una nuova lista operando una trasformazione sulla precedente. Per fare ciò esistono diversi modi, quello più semplice è usare un ciclo for così

Trasfomazioni con il for

[113]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']


nuova_lista = []
for animale in animali:  # ad ogni ciclo la variabile 'animale' contiene un nome preso dalla lista 'animali'
    nuova_lista.append(animale.capitalize())   # aggiungiamo alla nuova lista il nome dell'animale corrente, con la prima lettera maiuscola
nuova_lista

#vediamo che succede con Python tutor
jupman.pytut()
[113]:
Python Tutor visualization

Nota importante: i metodi sulle stringhe non modificano mai la stringa originale, ma ne generano sempre una nuova. Quindi la lista originale animali conterrà ancora le stringhe originale senza modifiche:

[114]:
animali
[114]:
['cani', 'gatti', 'scoiattoli', 'alci']

✪ ESERCIZIO: Prova a scrivere qua sotto un ciclo for (senza usare il copia e incolla!) che scorre la lista dei nomi degli animali e crea un’altra lista che chiameremo m in cui tutti i caratteri dei nomi degli animali sono in maiuscolo (usa il metodo .upper())

Mostra soluzione
[115]:

animali = ['cani', 'gatti', 'scoiattoli', 'alci'] # scrivi qui

Trasformazioni con le list comprehension

Riferimenti: SoftPython - Sequenze

La stessa identica trasformazione di sopra si potrebbe attuare con una cosiddetta list comprehension, che servono per generare nuove liste eseguendo la stessa operazione su tutti gli elementi di una lista esistente di partenza. Come sintassi imitano le liste, infatti iniziano e finiscono con le parentesi quadre, ma dentro contengono un for speciale per ciclare dentro un sequenza :

[116]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.capitalize() for animale in animali]
[117]:
nuova_lista
[117]:
['Cani', 'Gatti', 'Scoiattoli', 'Alci']

Vediamo che succede con Python tutor:

[118]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.capitalize() for animale in animali]

jupman.pytut()
[118]:
Python Tutor visualization

✪ ESERCIZIO: Prova qua sotto ad usare una list comprehension per mettere tutti i caratteri in maiuscolo

Mostra soluzione
[119]:

animali = ['cani', 'gatti', 'scoiattoli', 'alci'] # scrivi qui

Filtrare con le comprehension: Volendo, possiamo anche filtrare i dati usando un if speciale da mettere alla fine della comprehension. Per esempio potremmo selezionare solo gli animali la cui lunghezza del nome è di 4 caratteri:

[120]:
[animale.upper() for animale in animali if len(animale) == 4]
[120]:
['CANI', 'ALCI']

Trasformazioni con le map

Un’altro modo ancora per trasformare una lista in una nuova è usare l’operazione map, che a partire da una lista, ne genera un’altra applicando ad ogni elemento della lista di partenza una funzione f che passiamo come parametro. Per risolvere lo stesso esercizio precedente, si potrebbe per esempio creare al volo con lambda una funzione f che mette la prima lettera di una stringa in maiuscolo, e poi si potrebbe chiamare la map passando la f appena creata:

[121]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']


f = lambda animale: animale.capitalize()

map(f, animali)
[121]:
<map at 0x7f3ba80e2150>

Purtroppo il risultato non è esattamente la lista che volevamo. Il problema è che Python 3 aspetta a ritornarci una lista vera e propria, e invece ci ritorna un iteratore. Come mai? Python 3 per ragioni di efficienza spera che non non andremo mai ad usare nessun elemento della nuova lista, evitandogli di fatto la fatica di applicare la funzione a tutti gli elementi della lista originale. Ma noi possiamo forzarlo a darci la lista che vogliamo usando la funzione list:

[122]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

f = lambda animale: animale.capitalize()

list(map(f, animali))
[122]:
['Cani', 'Gatti', 'Scoiattoli', 'Alci']

Per avere un esempio totalmente equivalente ai precedenti, possiamo assegnare il risultato a nuova_lista:

[123]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

f = lambda animale: animale.capitalize()

nuova_lista = list(map(f, animali))
[124]:
nuova_lista
[124]:
['Cani', 'Gatti', 'Scoiattoli', 'Alci']

Un vero hacker Python probabilmente preferirà scrivere tutto in una sola linea, così:

[125]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = list(map(lambda animale: animale.capitalize(), animali))
[126]:
nuova_lista
[126]:
['Cani', 'Gatti', 'Scoiattoli', 'Alci']

✪ ESERCIZIO: la lista originale animali è cambiata? Controlla.

✪ ESERCIZIO: Data una lista numeri = [3, 5, 2, 7] prova a scrivere una map che genera una nuova lista con i numeri raddoppiati, come [6, 10, 4, 14]:

Mostra soluzione
[127]:

numeri = [3, 5, 2, 7] # scrivi qui

Matrici

Finita la presentazione, è ora di sforzarsi un po’ di più. Vediamo brevemente matrici come liste di liste. Per approfondire, guardare i riferimenti.

Riferimenti:

✪✪ ESERCIZIO: Date le due liste con nomi di animali e corrispondente aspettativa di vita in anni:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

Scrivere nella cella sotto del codice che generi una lista di liste da due elementi, così:

[   ['cane', 12],    ['gatto', 14],    ['pellicano', 30],    ['scoiattolo', 6],    ['aquila', 25] ]

Mostra soluzione
[128]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui

✪✪ ESERCIZIO modificare scrivendolo qua sotto il codice dell’esercizio precedente nella versione con il normale ciclo for per filtrare solo le specie con aspettativa di vita superiore ai 13 anni, così da ottenere questo risultato:

[['gatto', 14], ['pellicano', 30], ['aquila', 25]]
Mostra soluzione
[129]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui

ESERCIZIO Scrivi qua sotto del codice con un normale ciclo for per filtrare solo le specie con aspettativa di vita superiore ai 10 anni e inferiore ai 27, così da ottenere questo risultato:

[['cane', 12], ['gatto', 14], ['aquila', 25]]
Mostra soluzione
[130]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui

Funzione zip

La funzione zip prende due liste e produce una sequenza nuova, in cui mette coppie di elementi come tuple (che ricordiamo sono come le liste ma immutabilii), abbinando il primo elemento della prima lista a primo elemento della seconda lista, il secondo elemento della prima lista al secondo elemento della secondo e così via :

[131]:
list(zip(['a','b','c'], [5,2,7]))
[131]:
[('a', 5), ('b', 2), ('c', 7)]

Perchè abbiamo messo anche list nell’esempio? Perchè zip ha lo stesso problema della map, cioè non materializza subito una lista come forse vorremmo:

[132]:
zip(['a','b','c'], [5,2,7])
[132]:
<zip at 0x7f3ba80fe8c0>

✪✪✪ ESERCIZIO: Come vedi con la zip abbiamo ottenuto un risultato simile a quello del precedente esercizio, ma abbiamo tuple con parentesi tonde invece di liste con parentesi quadre. Riusciresti aggiungendo una list comprehension o una map ad ottenere lo stesso identico risultato?

  • per convertire una tupla in una lista, usa la funzione list:

[133]:
list(  ('ciao', 'soft', 'python')  )  # all'interno abbiamo messo una tupla, delimitata da parentesi tonde
[133]:
['ciao', 'soft', 'python']
Mostra soluzione
[134]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui - soluzione con list comprehension

Mostra soluzione
[135]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui - soluzione con map

✪✪✪ ESERCIZIO: svolgi l’esercizio precedente filtrando gli animali con aspettativa di vita superiore ai 13 anni, usando la zip e una list comprehension

Mostra soluzione
[136]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui

✪✪ ESERCIZIO: Date le due liste con nomi di animali e corrispondente aspettativa di vita in anni come sopra, scrivere nella cella sotto del codice che con un normale ciclo for generi un dizionario che associa alla specie l’aspettativa di vita, così:

{
 'aquila': 25,
 'cane': 12,
 'gatto': 14,
 'pellicano': 30,
 'scoiattolo': 6
}

ATTENZIONE: l’ordine non ha importanza!

A seconda della versione esatta di Python che avete e di come il dizionario viene creato, l’ordine dei campi quando viene stampato potrebbe differire dall’esempio. Questo è perfettamente normale, perchè le chiavi di un dizionario sono da intendersi come un insieme senza ordine particolare. Se volete essere sicuri di trovare le chiavi stampate nell’ordine in cui sono state inserite, dovete usare un OrderedDict

Mostra soluzione
[137]:

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila'] anni = [12,14,30,6,25] # scrivi qui

Per ottenere lo stesso risultato in una linea, è possibile usare la funzione zip come fatto negli esercizi precedenti, e poi la funzione dict che crea un dizionario a partire dalla lista di coppie di elementi generata dallo zip:

[138]:
dict(zip(animali, anni))
[138]:
{'cane': 12, 'gatto': 14, 'pellicano': 30, 'scoiattolo': 6, 'aquila': 25}

✪✪ ESERCIZIO: Data una lista di prodotti contenente a sua volta liste ciascuna con categoria, marca e quantità di confezioni vendute:

vendite = [
    ['pomodori', 'Santini', 5],
    ['pomodori', 'Cirio', 1],
    ['pomodori', 'Mutti', 2],
    ['cereali', 'Kelloggs', 3],
    ['cereali', 'Choco Pops', 8],
    ['cioccolata','Novi', 9],
    ['cioccolata','Milka', 4],
]

Usando un normale ciclo for, scrivi del codice Python nella cella sotto per creare un dizionario in cui le chiavi sono le categorie e i valori sono la somma delle confezioni vendute per quella categoria:

{
 'cereali': 11,
 'cioccolata': 13,
 'pomodori': 8
}

SUGGERIMENTO: fare attenzione ai due casi, quando il dizionario da ritornare ancora non contiene la categoria estratta dalla lista correntemente in esame e quando invece già la contiene:

Mostra soluzione
[139]:

vendite = [ ['pomodori', 'Santini', 5], ['pomodori', 'Cirio', 1], ['pomodori', 'Mutti', 2], ['cereali', 'Kelloggs', 3], ['cereali', 'Choco Pops', 8], ['cioccolata','Novi', 9], ['cioccolata','Milka', 4], ] # scrivi qui

Approfondimenti

Strumenti e script: Se vuoi approfondire come eseguire il codice in editor diversi da Jupyter e avere un’idea più precisa dell’architettura di Python, ti invitiamo a leggere Strumenti e script

Gestione errori e testing: Per capire come si gestiscono le situazioni di errore in genere guarda il foglio separato Gestione errori e testing, serve anche per capire come eseguire alcuni esercizi della Part A - Fondamenti.