# --- # jupyter: # jupytext: # formats: ipynb,py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.15.2 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # %% [markdown] editable=true slideshow={"slide_type": "slide"} # # Fondamenti di Programmazione # # # **Andrea Sterbini** # # lezione 4 - 5 ottobre 2023 # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## RECAP # - stringhe # - slice # - variabili e riferimenti # - oggetti e metodi # - funzioni # - if-elif-else # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Operazioni logiche # - **A and B** (vera se A e B sono entrambi veri) # - **A or B** (vera se almeno uno è vero) # - **not A** (vera se A è falso e viceversa) # # PRECEDENZA: **not** --> **and** --> **or** # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## If-elif-else # ```python # if condizione1: # istruzioni eseguite se è vera la condizione1 # elif condizione2: # istruzioni eseguite se è falsa condizione1 ed è vera condizione2 # ... # else: # istruzioni eseguite se tutte le condizioni sono false # ``` # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Momento Wooclap (booleani e if-then-else) # ![wooclap.png](wooclap.png) # %% editable=true slideshow={"slide_type": "subslide"} ## SOLUZIONI True and not False or True and False or not True # è come (True and (not False)) or (True and False) or (not True) # ovvero (True and True) or False or False # quindi True or False or False # %% editable=true slideshow={"slide_type": "subslide"} # Ricordiamo che True == 1 e False == 0 True+False/True+True*True-False # è lo stesso che 1 + 0/1 + 1*1 - 0 # ovvero 1 + (0/1) + (1*1) - 0 # quindi 1 + 0.0 + 1 - 0 # notate il float # %% editable=true slideshow={"slide_type": "subslide"} is_raining = True got_umbrella = False have_money = True if not is_raining: print('go out') elif not got_umbrella and have_money: print('buy umbrella and go out') elif got_umbrella: print('go out since got umbrella') else: print('stay home') # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Namespaces, nomi e identificatori # # **QUALI** sono i nomi ammessi come **identificatori** in python? # - iniziano per **carattere alfabetico** oppure '_' (lineetta bassa) # - non contengono spazi # %% [markdown] # ### Identificatori PARLANTI # # Date SEMPRE un nome esplicativo alle funzioni, variabili, argomenti e classi # # **"Programma sempre come se il ragazzo che dovrà manutenere il tuo codice sia uno psicopatico violento che sa dove vivi."** Martin Golding # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # E **DOVE** si trovano i nomi delle variabili, funzioni e classi? # %% [markdown] editable=true slideshow={"slide_type": "fragment"} # Nei **NAMESPACE** (tabelle dei nomi) # # Ce ne sono almeno 3, uno dentro l'altro: # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - namespace **BUILT-IN** (quello più esterno) che contiene: # - tutte le funzioni e le variabili dell'interprete Python # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - namespace **GLOBALE** (quello più esterno) che contiene: # - le variabili **GLOBALI** accessibili a tutte le funzioni che le seguono nel file # - le funzioni e le classi definite nel file # - i moduli/librerie importati con **import nomemodulo** # %% [markdown] editable=true slideshow={"slide_type": "fragment"} # - namespace di **MODULO** (i moduli importati) che contengono: # - tutte le variabili, funzioni e classi definite nel modulo # # Per usare una variabile/funzione si usa la sintassi # **nomemodulo.variabile** oppure **nomemodulo.funzione(argomenti)** # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - namespace **LOCALE** alla funzione in esecuzione, che contiene: # - gli **argomenti formali** della funzione, con i valori forniti quando è stata chiamata # - le variabili **locali** definite dentro la funzione # - e che scompaiono quando la funzione ha finito # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # Ogni volta che usate un identificatore, verrà cercato in ordine **LEGB**: # 1. nel namespace della **funzione** (**L**ocal) # 2. poi nei namespace che lo racchiudono (**E**nclosing) # - possono essere **funzioni** oppure **moduli** # 3. poi nel namespace **globale** # 4. infine nel namespace **built-in** # # QUINDI: una variabile locale può NASCONDERE una variabile globale con lo stesso nome # %% editable=true slideshow={"slide_type": "subslide"} ### ESEMPIO G = 42 # definisco una variabile globale def funzione_senza_effetti_collaterali(valore): 'funzione che definisce G come variabile locale' G = valore print(G, 'dentro la funzione il valore di G è quello locale') print(G, 'prima di chiamare la funzione') funzione_senza_effetti_collaterali(555) print(G, 'dopo aver chiamato la funzione il valore è quello globale') # %% editable=true slideshow={"slide_type": "subslide"} def funzione_CON_effetti_collaterali(valore): global G # voglio usare la variabile globale e non una nuova locale G = valore print(G, 'dentro la funzione la variabile G è quella globale') print(G, 'prima di chiamare la funzione') funzione_CON_effetti_collaterali(666) print(G, 'dopo aver chiamato la funzione il valore è cambiato') # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Per aiutarvi # Negli HW le variabili GLOBALI (e gli attributi di classe) sono proibiti # # Aggiungeremo un test che controlla che non usiate GLOBALI o attributi di classe # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Ancora sulle funzioni # ```python # def nome_funzione(argomenti): # corpo della funzione # return risultato # ``` # %% [markdown] editable=true slideshow={"slide_type": "fragment"} # **NOTA:** # - l'istruzione **return** può essere ovunque nel corpo della funzione, # ne ferma l'esecuzione in quel punto # **fornendo al programma chiamante** (tornando) il valore indicato # - se NON si esegue return la funzione torna il valore speciale **`None`** # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # **Reminder:** Le variabili locali nascono alla chiamata della funzione e scompaiono al suo completamento (return) # # **ATTENZIONE:** gli argomenti sono **variabili locali** e potete modificarli # - se si tratta di valori **immutabili** il programma chiamante **NON se ne accorgerà** # - se si tratta di valori **mutabili e ne modificate il contenuto** il programma chiamante **se ne accorgerà** # - se invece sostituite il **riferimento** della variabile locale, il programma principale **NON se ne accorgerà** # %% editable=true slideshow={"slide_type": "subslide"} nomi = ['Paperino', 'Topolino', 'Minnie', 'Annabella', 'Gastone'] def togli_terza(parole): "qui modifico la lista togliendo l'elemento a indice 2" parole.pop(2) # modifico l'oggetto riferito def sostituisci_tutte_non_distruttiva(parole): "qui rimpiazzo nella variabile locale 'parole' una nuova lista" parole = ['uno', 'due', 'tre'] # sostituisco il RIFERIMENTO def sostituisci_tutte_distruttiva(parole): "qui rimpiazzo nella variabile locale 'parole' una nuova lista" parole[:] = ['uno', 'due', 'tre'] # sostituisco il RIFERIMENTO print(nomi, '\tlista iniziale') togli_terza(nomi) print(nomi, '\t\tdopo aver tolto il 3° elemento') sostituisci_tutte_non_distruttiva(nomi) print(nomi, '\t\tdopo sostituisci_tutte_non_distruttiva') sostituisci_tutte_distruttiva(nomi) print(nomi, '\t\t\t\t\t\tdopo sostituisci_tutte_distruttiva') # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Ancora funzioni: argomenti OBBLIGATORI e OPZIONALI # # Gli **argomenti formali** nella definizione della funzione possono essere # - obbligatori, posizionali, (**sempre all'inizio** della lista) # - opzionali, **con un valore di default** da usare se il valore attuale non viene fornito (**sempre alla fine**) # - PRIMA gli obbligatori POI gli opzionali con i loro default # # Nella chiamata mettete prima i **valori attuali obbligatori**,
poi gli **opzionali** per posizione oppure per nome # %% editable=true slideshow={"slide_type": "subslide"} # supponiamo di voler concatenare 3 parole # ad una lista variabile di altre parole def concatena(obb1, obb2, opz3=42, opz4=None): if not isinstance(opz3, str): # se il 3° arg NON è una stringa opz3 = str(opz3) # lo trasformo in stringa if opz4 is None: # se il 4° arg non c'è opz4 = ['viva', 'Topolin'] # uso una lista di valori preconfezionata return ' '.join([obb1, obb2, opz3] + opz4) # gli argomenti opzionali sono sia posizionali che usabili per nome concatena('Minni', 'Paperino', 'Paperoga', ['Ciccio']) # %% editable=true slideshow={"slide_type": "subslide"} concatena('Minni', 'Paperino', 'Paperoga', opz4=['Pluto']) # %% editable=true slideshow={"slide_type": "subslide"} concatena('Minni', 'Paperino', opz4=['Ciccio']) # %% editable=true slideshow={"slide_type": "subslide"} concatena('Minni', 'Paperino') # %% editable=true slideshow={"slide_type": "subslide"} # per passarli *fuori sequenza* va usato il nome # in realtà potete anche passare tutti gli argomenti per nome # in qualsiasi ordine concatena(obb2='Minni', opz3='Paperino', obb1='Paperoga', opz4=['Ciccio']) # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ### Un errore molto difficile da notare: valori di default modificabili # Python crea i valori di default **nel momento della definizione della funzione** (e non alla sua CHIAMATA) # # Per cui i valori di default **vengono riusati in tutte le chiamate** # %% [markdown] editable=true slideshow={"slide_type": "slide"} # - se sono immutabili non c'è problema
(numeri, stringhe, None, tuple) # - se sono mutabili **NON DOVETE CAMBIARLI**
altrimenti in altre chiamate saranno diversi! # - se vi serve che siano modificati **USATE `None` come default**
e create il valore che vi serve come default SOLO a run-time # %% editable=true slideshow={"slide_type": "subslide"} # mi aspetterei che ad ogni chiamata senza parametri # X sia valorizzato con una nuova lista vuota # ma non è così, la lista è creata una sola volta # nel momento della definizione della funzione def modifico_il_default(X=[]): X.append(12) # modifico la lista X return X print( modifico_il_default()) # non passo nessun valore print( modifico_il_default()) # non passo nessun valore print( modifico_il_default()) # non passo nessun valore # si vede come la lista X cambia mano a mano # %% editable=true slideshow={"slide_type": "subslide"} # implementazione CONSIGLIATA def non_modifico_il_default(X=None): # costruisco una nuova lista vuota per ogni chiamata senza parametri if X is None: X = [] X.append(12) return X print( non_modifico_il_default()) # non passo nessun valore print( non_modifico_il_default()) # non passo nessun valore print( non_modifico_il_default()) # non passo nessun valore # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Per aiutarvi # Negli HW gli argomenti con default mutabile saranno proibiti # # Aggiungeremo un test che controlla che non usiate argomenti di default mutabili # %% [markdown] editable=true slideshow={"slide_type": "slide"} # # Cicli ed iterazione # ## se sapete quante iterazioni dovete fare usate il FOR # **Sintassi:** # ```python # # alla variabile viene assegnato il prox valore # for variabile in sequenza: # blocco di codice da ripetere per ogni valore # else: # opzionale # blocco che viene eseguito se si è usciti # normalmente (senza break) # ``` # %% editable=true slideshow={"slide_type": "subslide"} # ESEMPIO for X in [1, 2, 3, 4]: # ripeto 4 volte, con X che prende i valori 1, 2, 3, 4 print(X) # l'istruzione print # %% [markdown] editable=true slideshow={"slide_type": "fragment"} # Nel corpo del ciclo posso usare # ```python # break # per uscire immediatamente dal ciclo # # e proseguire DOPO tutto il FOR # continue # per saltare al prossimo elemento del FOR # # senza completare il blocco indentato # ``` # %% editable=true slideshow={"slide_type": "subslide"} # ESEMPIO for X in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: if X % 2 == 0: continue # salto tutti i numeri pari if X == 13: break # esco se incontro il valore 13 print(X) else: print('li ho stampati tutti') # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## se NON sapete quante iterazioni fare usate WHILE # ```python # while condizione_vera: # blocco di codice da ripetere # aggiornamento della condizione # else: # opzionale # blocco di codice eseguito se NON si esce # con break # ``` # %% editable=true slideshow={"slide_type": "subslide"} # ESEMPIO X = 0 while X < 20: X += 1 # aggiorno la condizione if X % 2 == 0: continue if X == 27: break print(X) else: print('li ho stampati tutti') # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Generatore di sequenze: oggetto che fornisce un elemento per volta # #### La funzione **range** # **range(fine)** | | **0, 1, 2, 3, 4.... (fine-1)** # -----------------|--|----------------------------- # **range(inizio, fine)** | | **inizio, inizio+1, .... , fine-1** # **range(inizio, fine, incremento)** | | **inizio, inizio+incremento, ...., fine-1** # %% editable=true slideshow={"slide_type": "fragment"} ## range crea un oggetto che fornisce un nuovo valore ogni volta ## che gli viene richiesto dal for o da list R = range(10) for i in R: print(i, end=' ') R list(R) # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## I contenitori: # ### liste, tuple, dizionari, insiemi # - **liste**: `[ 1, 2, 3, 4, 5, ]` indicizzate e modificabili # - **tuple**: `( 1, 2, 3, 4, 5, )` indicizzate e immutabili # - **insiemi**: `{ 1, 2, 3, 4, 5, }` senza ripetizioni, NON indicizzati e mutabili # - **dizionari**: `{ 'a': 1, 'b': 2, 'c': 3, }` associazioni chiave unica -> valore, indicizzati sulle chiavi, modificabili # # %% editable=true slideshow={"slide_type": "subslide"} # Esempio: lista_valori = [2, 5, 7, 23, 45, 2, 7, 23, ] tupla_valori = tuple(lista_valori) # converto la lista in tupla set_valori = set(lista_valori) # converto la lista in set dizionario = { 'a': 1, 'b': 2, 'c': 3, } lista_valori, tupla_valori, set_valori, dizionario # %% editable=true slideshow={"slide_type": "subslide"} ## le liste sono indicizzate E **modificabili** print(lista_valori[4]) lista_valori[5] = 666 print(lista_valori) # %% editable=true slideshow={"slide_type": "fragment"} ## gli insiemi NON sono indicizzati e sono **modificabili** print(set_valori) print(set_valori.pop()) # estraggo un elemento a caso set_valori.add(666) # aggiungo un elemento print(set_valori) set_valori[4] # ERRORE!!! # %% editable=true slideshow={"slide_type": "fragment"} ## le tuple sono indicizzate E **immutabili** print(tupla_valori[4]) tupla_valori[5] = 666 ### se provo a modificarla ERRORE! # %% editable=true slideshow={"slide_type": "subslide"} # i dizionari sono indicizzati dalle chiavi e **modificabili** print(dizionario.keys()) # estraggo le chiavi -> oggetto print(list(dizionario.keys())) # estraggo le chiavi -> lista print(dizionario['a']) # stampo il valore associato ad 'a' dizionario['paperino'] = 42 # aggiungo una coppia chiave -> valore print(dizionario) # il dizionario è cambiato #dizionario['pluto'] # se la chiave non c'è ERRORE!!! print('pluto' in dizionario) print(list(dizionario.values())) { 'uno':1, 'due':2, 'uno':11 } # %% editable=true slideshow={"slide_type": "subslide"} # se voglio stampare gli elementi dei diversi contenitori for elemento in lista_valori: print(elemento, end=' ') # stampa seguita da spazio invece che '\n' print('\t\tlista_valori') # %% editable=true slideshow={"slide_type": "subslide"} for elemento in set_valori: print(elemento, end=' ') print('\t\tset_valori') # %% editable=true slideshow={"slide_type": "subslide"} for elemento in tupla_valori: print(elemento, end=' ') print('\t\ttupla_valori') # %% editable=true slideshow={"slide_type": "subslide"} # sfruttiamo gli assegnamenti multipli di Python for chiave,elemento in dizionario.items(): # items produce le coppie print(chiave,elemento) dizionario.items() # %% editable=true slideshow={"slide_type": "subslide"} #### come scandire un contenitore per valori for elemento in lista_valori: print(elemento, end=' ') print() # %% editable=true slideshow={"slide_type": "fragment"} #### come scandire un contenitore per indice for i in range(len(lista_valori)): print(i, lista_valori[i]) # %% editable=true slideshow={"slide_type": "subslide"} #### come scandire un contenitore per valori ma sapendone l'indice for indice,elemento in enumerate(lista_valori): print(indice, elemento) list(enumerate(lista_valori)) # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## E' "PROIBITO" modificare la lista
sulla quale si sta iterando? # What if elimino elementi dalla lista MENTRE la sto scandendo? # - sono nella posizione 3, # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - elimino l'elemento, # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - il 4° si sposta in posizione 3 # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - passo all'elemento in posizione 4 # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - e **MI PERDO QUELLO CHE ERA IN POSIZIONE 4!!!** # - e **HO ERRORE SULL'ULTIMO ELEMENTO!!!** # # Insomma, mi tiro via il tappeto da sotto i piedi!!! # %% editable=true slideshow={"slide_type": "subslide"} lista_interi = [ 0, 11, 22, 33, 44, 55, 66, 77, 88, ] for i in range(len(lista_interi)): print(lista_interi[i]) if i == 3: del lista_interi[i] # elimino l'elemento in posizione 3 # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## COME RISOLVERE? # # - **opzione 1**: scandisco la lista dalla fine all'inizio # - in questo modo le modifiche spostano elementi GIA' ESAMINATI # - ed inoltre gli indici esistono tutti (no IndexError) # - **oppure**: costruisco una nuova lista # - in questo modo non modifico la lista originale # - **in genere**: itero su una lista SENZA MODIFICARLA (o s una sua copia), e mi costruisco altre strutture dati # %% editable=true slideshow={"slide_type": "subslide"} # scansione a rovescio lista_interi = [ 11, 22, 33, 44, 55, 66, 77, 88, ] for i in range(len(lista_interi)-1, -1, -1): # range con incremento negativo print(lista_interi[i], end=' ') if i == 3: del lista_interi[i] print() print(lista_interi, 'lista_interi') # %% editable=true slideshow={"slide_type": "subslide"} # oppure costruisco una nuova lista nuova_lista = [] lista_interi = [ 11, 22, 33, 44, 55, 66, 77, 88, ] for i in range(len(lista_interi)): if i != 3: nuova_lista.append(lista_interi[i]) print(lista_interi[i], end=' ') print() print(lista_interi, 'lista_interi') print(nuova_lista, 'nuova_lista') # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Momento Wooclap # #### cosa stampa il programma ? # ![wooclap.png](wooclap.png) # %% slideshow={"slide_type": "subslide"} # Soluzione lista_valori = list(range(10)) somma = 0 for i in range(10): if i == len(lista_valori): # esco se sono finiti gli elementi break if i % 3 == 0: # per tutti i multipli di 3 somma += lista_valori[i] # li sommo print(lista_valori[i]) del lista_valori[i] # e li elimino print(somma) print(lista_valori) # valori rimasti nella lista # volevamo sommare 0 3 6 9 => 18 # e invece abbiamo sommato 0 4 8 => 12 # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Scorciatoie logiche per controllare i contenitori nei test if/then/else # # Spesso dobbiamo controllare se un contenitore è vuoto o contiene elementi (oppure se una variabile è 0 o diversa da 0). Per semplificare gli if-then-else: # - un contenitore vuoto vale come **False** # - un contenitore con almeno un elemento vale **True** # # Ed inoltre # - un valore 0 vale False # - un valore diverso da zero vale True # %% editable=true slideshow={"slide_type": "subslide"} ## Per controllarlo trasformiamo contenitori vuoti in booleani bool([]), bool(tuple()), bool({}), bool(set()) # %% editable=true slideshow={"slide_type": "fragment"} bool([1]), bool((2,)), bool({3:'tre'}), bool({4}) # %% editable=true slideshow={"slide_type": "fragment"} def stampa_lista(valori): # se la lista contiene almeno un elemento if valori: print(valori[0]) # stampo il primo stampa_lista(valori[1:]) # stampo gli altri dati = [1, 2, 3, 4, 5] stampa_lista(dati)