Python Base¶

Python Biella Group¶


Seconda serata, 10/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)

Recap sfide prima puntata¶

Vedere link

Controllo di flusso - if¶

Come eseguire codice solo se una condizione è vera?

Riferimenti: SoftPython - if

In [1]:
fatto_colazione, lavato_denti = True, True

if fatto_colazione and lavato_denti:
    print("fatto tutto !")
    print("posso uscire di casa.")
    
print("Fine.")    
fatto tutto !
posso uscire di casa.
Fine.
if ESPRESSIONE_BOOLEANA:
    BLOCCO ISTRUZIONI

Cosa fare se la condizione è falsa?

In [2]:
fatto_colazione, lavato_denti = True, False

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

print("Fine.")
NON posso uscire di casa.
Fine.
if ESPRESSIONE_BOOLEANA:
    BLOCCO ISTRUZIONI
else:
    ALTRO BLOCCO ISTRUZIONI

if: Attenzione¶

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

Per indentare, usa SEMPRE 4 spazi bianchi

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

Il comportamento di TAB dipende dal tuo editor

A seconda dell'editor che usi, premendo TAB potresti ottenere:

  • una sequenza di spazi bianchi (4 in Jupyter)
  • ...oppure un carattere speciale di tabulazione (da evitare)!

if - valori logici¶

In Python, gli oggetti 'vuoti' hanno valore logico False:

  • numero 0, oggetto None, la stringa vuota "", lista vuota [], ...

Tutto ciò che non è 'vuoto' è considerato True:

if ['Che', 'tempo', 'farà', 'domani?']:    
    print("Sole!")
else:
    print("Pioggia")
Sole!

Per altre cose 'strane', vedere: SoftPython - Booleani - Ordine di valutazione

if annidati¶

Si può anche mettere un if dentro l'altro (nested if).

Esempio (funziona esattamente come il precedente):

In [4]:
fatto_colazione, lavato_denti = True,True

if fatto_colazione:
    if lavato_denti:                        # NOTA: Questo blocco è indentato
        print("fatto tutto !")              #       rispetto all'if esterno
        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!

if in cascata: elif¶

In [11]:
caramelle = 3

if caramelle > 10:
    print('tante caramelle!')
elif caramelle > 5:
    print('abbastanza caramelle!')
elif caramelle > 0:
    print('poche caramelle!')    
else:
    print('Non ci sono caramelle!')
poche caramelle!
In [12]:
caramelle = 0

if caramelle > 10:
    print('tante caramelle!')
elif caramelle > 5:
    print('abbastanza caramelle!')
elif caramelle > 0:
    print('poche caramelle!')    
else:
    print('Non ci sono caramelle!')
Non ci sono caramelle!

Costrutto match (menzione)¶

oggetto = "Voglio un caffè"

match oggetto:
    case "Voglio un caffè":
        print("Preparo la moka...")
    case "Voglio una brioche":
        print("Scaldo la brioche..")
    case altro:
        print("Non ho capito cos'è", altro)
Preparo la moka...
  • per evitare di scrivere if complicati
  • molto flessibile e potente
  • SOLO da Python $\geq$ 3.10

Iterazione¶

Come compiere azioni su ogni elemento di una sequenza?

Cicli for

  • list comprehension

Cicli while

Riferimenti: SoftPython - controllo di flusso

Iterazione - Cicli for¶

In [13]:
animali = ['cani', 'gatti', 'scoiattoli']

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
  • abbiamo definito la variabile animale
  • per ogni elemento nella lista animali:

    • la variabile animale assume il valore dell'elemento
    • vengono eseguite le istruzioni dentro il blocco

Sequenza range¶

In [15]:
range(5)
Out[15]:
range(0, 5)

range(n) rappresenta una sequenza con i primi numeri da 0 incluso a n escluso

la sequenza è 'congelata'

Per materializzare i numeri, convertire esplicitamente a list:

In [16]:
list(range(5))
Out[16]:
[0, 1, 2, 3, 4]

for in range¶

Come incrementare un contatore ad ogni ciclo?

Possiamo usare range

Il for scorre automaticamente la sequenza:

In [17]:
for indice in range(5):
    print(indice)
0
1
2
3
4

A cosa serve for in range? 1/2¶

Per leggere da una lista possiamo usare gli indici:

In [18]:
animali = ['cani', 'gatti', 'scoiattoli']

for indice in range(len(animali)):        
    print(animali[indice])
cani
gatti
scoiattoli

A cosa serve for in range? 2/2¶

Per MODIFICARE celle esistenti di una lista, dobbiamo usare gli indici:

In [19]:
animali = ['cani', 'gatti', 'scoiattoli']

for indice in range(len(animali)):    
    animali[indice] = animali[indice].upper()  
    
print(animali)    
['CANI', 'GATTI', 'SCOIATTOLI']

Senza indici, non funziona:

In [20]:
animali = ['cani', 'gatti', 'scoiattoli']

for animale in animali:
    animale = animale.upper()  # SBAGLIATO, NON FA NULLA
print(animali)    
['cani', 'gatti', 'scoiattoli']

COMANDAMENTO: Non aggiungerai o toglierai mai elementi da una sequenza che iteri con un for !

In [21]:
lista = ['a','b','c','d','e']

for el in lista:
    lista.remove(el)   # PESSIMA IDEA

lista  # RISULTATO IMPREVEDIBILE  !!!!
Out[21]:
['b', 'd']

Per saperne di più: SoftPython - Modificare durante l'iterazione

List comprehension¶

Espressione per generare una NUOVA lista a partire da una sequenza

In [22]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

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

nuova_lista
Out[22]:
['CANI', 'GATTI', 'SCOIATTOLI', 'ALCI']
In [23]:
animali
Out[23]:
['cani', 'gatti', 'scoiattoli', 'alci']
[ ESPRESSIONE for VARIABILE in SEQUENZA ]
  • Sintassi imita le liste
  • esegue la stessa operazione su tutti gli elementi di una sequenza

Riferimenti: SoftPython - Sequenze

Per filtrare con le comprehension:

In [24]:
animali = ['cani', 'gatti', 'scoiattoli', 'alci']

[animale.upper() for animale in animali if len(animale) == 4]
Out[24]:
['CANI', 'ALCI']
  • aggiungere un if ESPRESSIONE_BOOLEANA speciale alla fine

Iterazione - Ciclo while¶

In [25]:
i = 1

while i < 4:
    print('Ho contato fino a', i)
    i += 1
    
print('Ciclo finito !')
Ho contato fino a 1
Ho contato fino a 2
Ho contato fino a 3
Ciclo finito !

Blocco di codice eseguito ripetutamente fintantochè una condizione booleana è vera

Riferimenti: SoftPython - cicli while

Quando usare while?¶

Tipicamente per

  • effettuare ricerche in una sequenza
  • aggiungere/togliere elementi dalla sequenza che si sta iterando
  • cicli infiniti

Altrimenti, consigliamo il for

Riferimenti: SoftPython - while - Modificare sequenze

Esempio while - cerca e togli in sequenza¶

Pesca carte da mazzo (da destra) finchè trova cuori

In [26]:
mazzo = ['3 di cuori','2 di picche','9 di cuori','5 di quadri','8 di fiori']
carta = ''
In [27]:
print("mazzo:", mazzo)
while len(mazzo) > 0 and 'cuori' not in carta:
    carta = mazzo.pop()  # rimuove ultima carta dal mazzo        
    print("pescato", carta)
    print("mazzo:", mazzo)
    
print("Uscito dal ciclo!")
mazzo: ['3 di cuori', '2 di picche', '9 di cuori', '5 di quadri', '8 di fiori']
pescato 8 di fiori
mazzo: ['3 di cuori', '2 di picche', '9 di cuori', '5 di quadri']
pescato 5 di quadri
mazzo: ['3 di cuori', '2 di picche', '9 di cuori']
pescato 9 di cuori
mazzo: ['3 di cuori', '2 di picche']
Uscito dal ciclo!

Iterazione - Performance¶

Python è un linguaggio intepretato -> lento..

Solo dove serve ottimizzare:

  • evitare cicli e usare librerie specializzate

    (vedi tutorial numpy, pandas, ..)

  • oppure compilare Python 'ristretto' in C (Cython, Mypyc, ...)

Iterazione - sfide¶

  • Testo storto (for)
  • Trivellum (while)

Sfida - testo storto¶

✪✪ Requisiti: stringhe, liste, if, for

Dato un testo di caratteri con diversa capitalizzazione, metti nella variabile tradotto il testo con la capitalizzazione invertita e poi STAMPALO

  • SUGGERIMENTO: per verificare se un carattere è minuscolo, usa il metodo .islower()

Esempio - dato:

testo = "CiAo QuEsTo E' uN TeStO sToRto"

dopo il tuo codice dovrebbe risultare:

>>> print(tradotto)
cIaO qUeStO e' Un tEsTo StOrTO
In [28]:
testo = "CiAo QuEsTo E' uN TeStO sToRto"   # cIaO qUeStO e' Un tEsTo StOrTO
#testo = "gInGillo"                        # GiNgILLO
tradotto = ''

# scrivi qui

Sfida - Trivellum¶

✪✪ La compagnia mineraria Trivellum ha scoperto un pozzo di cobalto. Nel pozzo si trovano diversi strati, ognuno contenente una lega di diversa composizione: una volta trivellato, lo strato viene suddiviso in blocchi che vengono poi issati su un carrello per il successivo trasporto.

Scrivi del codice che MODIFICA la variabile pozzo togliendo gli strati, e MODIFICA la variabile carrello aggiungendo i vari blocchi scavati.

  • USA un ciclo while
  • STAMPA i vari passaggi
  • NON riassegnare pozzo nè carrello (quindi niente pozzo = ... o carrello = ...)

vedi slide successiva...

Esempio - dati:

pozzo = ['███','▓▓▓','▒▒▒', '░░░']    # <-- cima del pozzo
carrello = []

Il tuo programma deve stampare:

il pozzo è: ['███', '▓▓▓', '▒▒▒', '░░░']
Trivello lo strato ░░░ e lo divido nei blocchi ['░', '░', '░']

il pozzo è: ['███', '▓▓▓', '▒▒▒']
Trivello lo strato ▒▒▒ e lo divido nei blocchi ['▒', '▒', '▒']

il pozzo è: ['███', '▓▓▓']
Trivello lo strato ▓▓▓ e lo divido nei blocchi ['▓', '▓', '▓']

il pozzo è: ['███']
Trivello lo strato ███ e lo divido nei blocchi ['█', '█', '█']

Il pozzo finale è   : []
Il carrello finale è: ['░', '░', '░', '▒', '▒', '▒', '▓', '▓', '▓', '█', '█', '█']
In [30]:
carrello = []
pozzo = ['███','▓▓▓','▒▒▒', '░░░']  # <-- cima del pozzo

#pozzo = ['┼┼','┤├','┐┌', '╗╔', '║║']  #  ['║', '║', '╗', '╔', '┐', '┌', '┤', '├', '┼', '┼']

# scrivi qui

Funzioni¶

Una funzione prende dei parametri e li usa per effettuare cambiamenti nel sistema o produrre qualche risultato.

Riferimenti: SoftPython - funzioni

In [32]:
def mia_stampa(x,y):   
    print('Ora stamperemo la somma di due numeri')
    print('La somma è %s' % (x + y))    

Possiamo chiamare la funzione così:

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

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

Ricordati i due punti : alla fine della riga !!

Vedi in Python Tutor

Side effects¶

Una funzione ha side effects quando modifica l'ambiente

Esempi:

  • illuminare i pixel sullo schermo con print
  • scrivere su file
  • richiedere input manuale all'utente

Funzione che RITORNA un valore¶

In [34]:
def mia_somma(x,y):
    s = x + y
    return s    
In [35]:
risultato = mia_somma(3,5)
In [36]:
risultato
Out[36]:
8

Per restituire un valore usabile fuori dalla funzione:

usa la parola chiave return seguita da una ESPRESSIONE

Vedi in Python Tutor

E se ci dimentichiamo il return ?¶

In [37]:
def mia_somma_sbagliata(x,y):
    x + y    

risultato = mia_somma_sbagliata(5,3)
In [38]:
risultato  # Jupyter non mostra niente!
In [39]:
print(risultato)  # forziamo stampa con print
None
In [40]:
def mia_somma_corretta(x,y):
    return x + y  

risultato = mia_somma_corretta(5,3)
print(risultato)
8

Funzioni che MODIFICANO input¶

In [41]:
def ordina(lista):
    """MODIFICA lista in modo che sia ordinata in-place
    """
    lista.sort()

numeri = [7,4,9,8]

ordina(numeri)
In [42]:
print(numeri)
[4, 7, 8, 9]

Vedi in Python Tutor

Funzioni che MODIFICANO input e RITORNANO¶

In [43]:
def pesca(lista):
    """MODIFICA lista rimuovendo l'ultimo elemento e lo RITORNA
    """    
    return lista.pop()

mazzo = ["9 di quadri","4 di picche","6 di cuori","7 di fiori"]

carta = pesca(mazzo)
In [44]:
print(carta)
7 di fiori
In [45]:
print(mazzo)
['9 di quadri', '4 di picche', '6 di cuori']

Vedi in Python Tutor

Argomenti keyword¶

Si possono aggiungere argomenti di default alla fine:

In [46]:
def ripeti(stringa, volte=3):    
    return stringa * volte

Quando si chiama la funzione si può:

In [47]:
ripeti('Rotola')             # omettere l'argomento di default
Out[47]:
'RotolaRotolaRotola'
In [48]:
ripeti("Rotola", volte=7)    # specificarlo per nome
Out[48]:
'RotolaRotolaRotolaRotolaRotolaRotolaRotola'
In [49]:
ripeti("Rotola",  2)         # scriverlo direttamente
Out[49]:
'RotolaRotola'

Argomenti keyword mutabili 1/2¶

ATTENZIONE: NON mettere argomenti di defaut mutabili

Lo stesso oggetto verrà condiviso da tutte le invocazioni della funzione!

In [50]:
def tragedia(lista=[]):
    lista.append('occhio!')
    print(lista)
In [51]:
tragedia()  # prima invocazione: sembra a posto..
['occhio!']
In [52]:
tragedia()  # seconda invocazione: guai!
['occhio!', 'occhio!']

Argomenti keyword mutabili 2/2¶

In [53]:
def meglio(lista=None):
    if lista == None:
        lista = []
    lista.append('ok')
    print(lista)
        
meglio()  # prima invocazione
['ok']
In [54]:
meglio()  # seconda invocazione
['ok']

Variabili esterne¶

Da dentro una funzione, possiamo leggere variabili esterne:

In [55]:
muro = "bianco"

def guarda():    
    print('Vedo un muro', muro)         
In [56]:
guarda()
Vedo un muro bianco

Variabili esterne: problemi¶

Ma se proviamo a riassegnare, Python crea una NUOVA variabile!

In [57]:
muro = "bianco"

def dipingi():                 
    print('Dipingo....')        
    muro = 'arancione'   # OCCHIO
    print('Esco')    
In [58]:
dipingi()
print('Adesso il muro è', muro)  
Dipingo....
Esco
Adesso il muro è bianco

Vedi in Python Tutor

Variabili esterne: global¶

Per evitare problemi, bisogna dichiarare la variabile esterna come global:

In [59]:
muro = "bianco"

def dipingi():        
    global muro          # CORRETTO 
    print('Dipingo....')        
    muro = 'arancione'   
    print('Esco')
    
dipingi()
print('Adesso il muro è', muro) 
Dipingo....
Esco
Adesso il muro è arancione

Vedi in Python Tutor

Funzioni lambda¶

Che cos'è una funzione? Un oggetto

Esempio: funzione len

In [60]:
len
Out[60]:
<function len(obj, /)>
In [61]:
len("rosa")         # invocazione
Out[61]:
4

Proviamo a creare una var mia_var che punta all'oggetto len:

In [62]:
mia_var = len

NOTA: non abbiamo aggiunto parametri a len!

Adesso possiamo usare mia_var esattamente come usiamo la funzione len:

In [63]:
mia_var("rosa")
Out[63]:
4

Funzioni lambda - esempio¶

Per creare una funzione 'al volo', usa la parola chiave lambda:

In [64]:
lambda x, y: x + y
Out[64]:
<function __main__.<lambda>(x, y)>
  • NON c'è il def
  • NON bisogna mettere return
  • DEVE stare su una riga sola

Una funzione lambda è un oggetto -> si può assegnare ad una variabile:

In [65]:
mia_somma = lambda x, y: x + y
In [66]:
mia_somma(3,5)
Out[66]:
8

funzioni lambda e def¶

Queste due scritture sono completamente equivalenti:

In [67]:
def mia_somma(x, y):
    return x + y
In [68]:
mia_somma = lambda x, y: x + y

Esempio: sorted e lambda¶

Aspettative di vita di animali:

In [69]:
animali = [('cane', 12), 
           ('gatto', 14), 
           ('pellicano', 30), 
           ('acquila', 25), 
           ('scoiattolo', 6)]

Come fare a ordinare per anni?

In [70]:
sorted(animali)   # SBAGLIATO
Out[70]:
[('acquila', 25),
 ('cane', 12),
 ('gatto', 14),
 ('pellicano', 30),
 ('scoiattolo', 6)]

Così è alfabetico...

Esempio: sorted key¶

Possiamo passare al parametro key una funzione che:

  • dato un elemento della lista...
  • ...produce un numero per ordinare

Scriviamo una lambda per estrarre aspettativa di vita:

In [71]:
sorted( animali, key=lambda tup: tup[1]  )
Out[71]:
[('scoiattolo', 6),
 ('cane', 12),
 ('gatto', 14),
 ('acquila', 25),
 ('pellicano', 30)]

Menzioni¶

  • Gestione errori e testing - tutorial SoftPython
  • Namespace and Scope
  • Positional-Only and Keyword-Only Parameters
  • Variable Number of Arguments
  • Decorator
  • Yield Statement and Asynchronous Functions

Funzioni - sfide¶

  • Pacman e i bulli
  • I biscotti danesi

Sfida - Pacman e i bulli¶

✪✪ Requisiti: funzioni, stringhe, for, if

Il nostro eroe dei labirinti incontra un gruppo di bulli che per prenderlo in giro iniziano a cantilenargli il suo iconico verso, storpiandolo: INVECE di "waka waka waka waka waka" gli cantano "waekai waekai waekai waekai" ed altre storpiature simili ottenute AGGIUNGENDO lettere al verso normale.

  • I bulli non aggiungono mai lettere corrette.
  • Aiuta PacMan scrivendo una funzione nobulli che pulisca dalle storpiature.
  • NON scrivere print nella funzione!

Esempio:

>>> bullo1 = "waekai waekai waekai waekai"
>>> res1 = nobulli(bullo1) 
>>> print(res1)
waka waka waka waka
  1. scrivi una prima versione nobulli(stringa) che assume che i caratteri desiderati da mantenere siano sempre 'w','a','k','a'
  2. scrivi una seconda versione nobulli2(stringa, mantieni) che prende anche in ingresso una stringa coi caratteri da mantenere

(vedi slide successiva)

In [73]:
# scrivi la funzione

# NON TOCCARE, queste linee devono funzionare
bullo1 = "waekai waekai waekai waekai"
bullo2 = "bwaka rwaka swaka twaka zwaka mmmwatka"
bullo3 = "eweaekea zwxarkma qwoagkpa"
res1 = nobulli(bullo1)   # Deve RITORNARE il verso pulito "waka waka waka waka"
print(res1)
res2 = nobulli(bullo2)   # Deve RITORNARE il verso pulito "waka waka waka waka waka waka"
print(res2)
res3 = nobulli(bullo3)   # Deve RITORNARE il verso pulito "waka waka waka"
print(res3)
waka waka waka waka
waka waka waka waka waka waka
waka waka waka

Sfida - I biscotti danesi¶

✪✪ Tornato a casa, per consolarsi dalle offese, PacMan si butta su una scatola di biscotti (di quelle con la confezione di latta rotonda).

Nella scatola ci sono 8 diversi tipi di biscotti e dopo averne mangiati un po' si accorge con orrore che ha lasciato che rimanesse un numero dispari di biscotti per alcune tipologie.

Ovviamente l'offesa va sanata: scrivi una funzione mangia che data una lista la MODIFICA per mangiare (e quindi togliere) un biscotto di tutti i tipi rimasti dispari.

  • NON scrivere return nè print nella funzione!

Esempio:

>>> scatola = [2, 5, 3, 8, 6, 24, 5, 3, 9] 
>>> mangia(scatola)
>>> print(scatola)
[2, 4, 2, 8, 6, 24, 4, 2, 8]

(vedi slide successiva..)

In [75]:
# scrivi la funzione



# NON TOCCARE, queste linee devono funzionare
scatola1 = [3, 3, 3, 3, 3]
scatola2 = [1, 3, 5, 7, 9]
scatola3 = [19, 3, 14, 1, 10, 9, 2, 16, 8, 7, 13, 11, 18, 17, 6, 5, 4, 12, 20, 15]

mangia(scatola1)  # deve MODIFICARE scatola1
mangia(scatola2)
mangia(scatola3)

print(scatola1) # Deve stampare [2, 2, 2, 2, 2]
print(scatola2) # Deve stampare [0, 2, 4, 6, 8]
print(scatola3) # Deve stampare [18, 2, 14, 0, 10, 8, 2, 16, 8, 6, 12, 10, 18, 16, 6, 4, 4, 12, 20, 14]


print(mangia([2,4,5,7])) # DEVE stampare None. Perchè ?
[2, 2, 2, 2, 2]
[0, 2, 4, 6, 8]
[18, 2, 14, 0, 10, 8, 2, 16, 8, 6, 12, 10, 18, 16, 6, 4, 4, 12, 20, 14]
None