# --- # 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] slideshow={"slide_type": "slide"} editable=true # # # Fondamenti di Programmazione # # # **Andrea Sterbini** # # lezione 5 - 9 ottobre 2023 # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## RECAP # - **if-elif-else** # - cicli **for** # - cicli **while** # - iteratore **range** # - **identificatori** # - funzioni e argomenti **obbligatori** o **opzionali** # - contenitori: **list, tuple, set, dict** # %% [markdown] slideshow={"slide_type": "slide"} editable=true # # Quesito con la Susi 1 (ed ora un po' di problem-solving) # # ![susi-1.jpg](susi-1.jpg) # %% [markdown] slideshow={"slide_type": "slide"} editable=true # ## Un primo approccio ... costruisco la stringa e trovo il carattere! # # - Per trovare la N-esima cifra # - costruisco la stringa con almeno N cifre # - ritorno il carattere in posizione N-1 # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # - Per costruire la stringa con almeno N cifre # - ripeto finchè non ho superato le 200 cifre # - concateno alla stringa corrente il prossimo intero # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # Manca qualcosa? # - l'inizializzazione delle variabili! # %% slideshow={"slide_type": "slide"} editable=true # Per calcolare la 200° cifra: # costruisco una stringa con le cifre (fin dove? 200?) # estraggo il 200° carattere (indice = 199) def cerca_carattere(N): testo = '' # si parte con una stringa vuota i = 1 # e dal numero 1 while len(testo) < N: # e si continua se il numero di cifre è insufficiente testo += str(i) # a concatenare le cifre del numero corrente i += 1 # ed a incrementarlo return testo[N-1] # e alla fine torniamo il carattere giusto # Semplice no? cerca_carattere(20000) # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ### E' una buona soluzione? # non tanto ... produce un mucchio di stringhe! # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Seconda idea che non crea stringhe inutili # - Per calcolare la 200° cifra: # - trovo in quale numero sta la 200° cifra # - e quante cifre sono rimaste da scandire # - la tiro fuori dal numero trovato # %% editable=true slideshow={"slide_type": "fragment"} def cerca_senza_stringhe(N): numero, mancanti = cerca_numero_e_rimanenti(N) # ritorno una coppia testo = str(numero) return testo[mancanti-1] # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - Per trovare in che numero sta la N-esima cifra # - scandisco i numeri da 1 in poi e per ciascuno # - trovo quante cifre ha # - se sono di meno delle cifre ancora da contare # - sottraggo le cifre da quelle ancora da contare # - altrimenti # - lo ritorno assieme al numero di cifre mancanti # %% editable=true slideshow={"slide_type": "subslide"} def cerca_numero_e_rimanenti(N): for i in range(1,N): # scandisco al più N-1 numeri cifre = num_cifre(i) # calcolo le cifre if cifre < N: # se sono poche N -= cifre # le sottraggo else: # altrimenti ci siamo return i, N # e torno il numero corrente e quante cifre mancano # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # Ma come trovo quante sono le cifre? # - opzione 1: lo trasformo in stringa e conto i caratteri (BLEAH!!!) # - opzione 2: ne calcolo il logaritmo in base 10 e sommo 1 # - opzione 3: genero le potenze di 10 finchè lo supero # %% slideshow={"slide_type": "fragment"} editable=true def opzione_1(X): 'calcolo il numero di cifre di un numero in base 10 trasformandolo in stringa' return len(str(X)) # genero un sacco di stringhette!!! opzione_1(100000), opzione_1(99999) # %% slideshow={"slide_type": "subslide"} editable=true from math import log10 # uso la funzione log10 del modulo math def opzione_2(X): 'calcolo il numero di cifre di un numero in base 10 con i logaritmi' # ne calcolo il logaritmo in base 10 # lo tronco ad intero e gli sommo 1 return int(log10(X))+1 opzione_2(100000), opzione_2(99999) # %% editable=true slideshow={"slide_type": "subslide"} def opzione_3(X): 'calcolo il numero di cifre di un numero in base 10 generando le potenze' numcifre = 1 potenza10 = 10 while potenza10 <= X: potenza10 *= 10 numcifre += 1 return numcifre opzione_3(100000), opzione_3(99999) # %% slideshow={"slide_type": "fragment"} editable=true N = 20000 num_cifre = opzione_1 # uso la prima opzione print(cerca_senza_stringhe(N), end=' ') num_cifre = opzione_2 # uso la seconda opzione print(cerca_senza_stringhe(N), end=' ') num_cifre = opzione_3 # uso la terza opzione print(cerca_senza_stringhe(N), end=' ') # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## Momento Wooclap: qual'è la 200 esima cifra? # ![wooclap.png](wooclap.png) # %% editable=true slideshow={"slide_type": "subslide"} # SOLUZIONE cerca_carattere(200), cerca_senza_stringhe(200), cerca_numero_e_rimanenti(200) # %% [markdown] slideshow={"slide_type": "slide"} editable=true # ## Moduli e import # Per caricare nel namespace GLOBALE le funzionalità realizzate in altri file si usa **`import`** # ```python # import modulo # solo 'modulo' viene inserito nel namespace # # chiamare la funzione # modulo.funzione(argomenti) # ``` # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # ```python # from modulo import funzione # solo 'funzione' -> namespace # # chiamare la funzione # funzione(argomenti) # ``` # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # ```python # from modulo import * # BAD CODER!!! NON USATELO!!! # # chiamare la funzione # funzione(argomenti) # ``` # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # **NOTA** # - A loro volta gli altri moduli possono importare altre librerie, nel proprio namespace di modulo # - Se un modulo è stato già importato viene riusato senza rileggerlo di nuovo dal file # %% [markdown] slideshow={"slide_type": "slide"} editable=true # # metodi dei Contenitori # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Operazioni sulle liste (list) # - **`elemento in L`** True se l'elemento è presente in L # - **`L1 + L2`** nuova lista concatenazione di L1 e L2 # - **`L1 * N`** replicazione N volte e concatenazione # - **`L.append(elemento)`** aggiunta di un elemento alla fine # - **`L[i]`** elemento all'indice **i** (lettura o assegnamento) # - **`L.pop()`** estrazione distruttiva dell'ultimo elemento (ERR se vuota) # - **`L.pop(i)`** estrazione distruttiva dell'elemento all'indice **i** (ERR se **i** non esiste) # - **`L.insert(i, elemento)`** inserisce l'elemento all'indice i (o in cima o in fondo) # %% slideshow={"slide_type": "fragment"} editable=true # Esempi di operazioni sulle liste L1 = [ 1, 2, 3, 4, 5, ] L2 = [ 11, 22, 33, ] L1 + L2 # %% slideshow={"slide_type": "fragment"} editable=true print(L1.pop(2)) # elimino quello a indice 2 L1.insert(78, 55) # inserisco ad indice 78 il valore 55 L1 # %% slideshow={"slide_type": "fragment"} editable=true L2[-2:] = [] # elimino gli ultimi due elementi L2 # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Altre operazioni sulle liste (list) # - **`L.remove(elemento)`** elimina la **prima occorrenza** dell'elemento (ERR se non presente) # - **`L.index(elemento)`** trova il primo indice in cui c'è l'elemento (ERR se non presente) # - **`L.count(elemento)`** conta l'elemento # - **`L.reverse()`** rovesciamento distruttivo della lista # - **`L.sort()`** ordinamento distruttivo della lista # %% slideshow={"slide_type": "fragment"} editable=true # Altri esempi di operazioni sulle liste L = [10, 43, 92, 1, -43, 90, -200, int('1') ] L.count(3) # %% slideshow={"slide_type": "fragment"} editable=true L.index(-43) # %% slideshow={"slide_type": "fragment"} editable=true L.sort() # riordinamento DISTRUTTIVO (modifica la lista) L # %% editable=true slideshow={"slide_type": "subslide"} help(list) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Operazioni sulle tuple # - **`elemento in T`** True se l'elemento è presente in T # - **`T1 + T2`** nuova tupla concatenazione di T1 e T2 # - **`T * N`** replicazione N volte e concatenazione # - **`T[i]`** accesso all'elemento all'indice i (SOLO lettura) # - **`L.index(elemento)`** trova il primo indice in cui c'è l'elemento (ERR se non presente) # - **`L.count(elemento)`** conta l'elemento # %% slideshow={"slide_type": "fragment"} editable=true # Esempi di operazioni sulle tuple T1 = 1, 2, 3, 4 T2 = 24, 52, 67, 31 T1 + T2 T1[2] = 55 # %% slideshow={"slide_type": "fragment"} editable=true T1[1:3] # %% editable=true slideshow={"slide_type": "subslide"} help(tuple) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Operazioni sugli insiemi (set) # - **`elemento in S`** True se elemento è presente in S # - **`S1 | S2`** oppure **`S1.union(S2)`** unione (or) # - **`S1 & S2`** oppure **`S1.intersection(S2)`** intersezione (and, elementi in comune) # - **`S1 - S2`** oppure **`S1.difference(S2)`** insieme degli el. di S1 che non sono in S2 # - **`S1 ^ S2`** oppure **`S1.symmetric_difference(S2)`** insieme degli elementi NON in comune (xor) # - **`S.pop()`** estrazione distruttiva di un el. (ERR if empty) # - **`S.add(elemento)`** aggiunta di un elemento # - **`S.remove(elemento)`** rimozione di un el. (ERR if missing) # - **`S1.update(S2)`** come **`S1 |= S2`** (distruttiva) # %% slideshow={"slide_type": "fragment"} editable=true # Esempi di operazioni sugli insiemi S1 = set(range(3,101,3)) # insieme dei multipli di 3 in [1..100] S2 = set(range(1,101)) - S1 # NON multipli di 3 print('S1 =',S1) print('S2 =',S2) # %% editable=true slideshow={"slide_type": "subslide"} help(set) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Operazioni sui dizionari (dict) # - **`key in D`** True se la chiave è presente # - **`D[key]`** accesso al valore con chiave key (R/W) (ERR se non presente) # - **`D.keys()`** elenco delle chiavi (che sono uniche) # - **`D.values()`** elenco dei valori (con duplicati) # - **`D.items()`** elenco delle coppie (chiave, valore) # - **`D.popitem()`** torna l'ultima coppia (k,v) # e la rimuove # - **`D1 | D2`** nuovo dizionario con tutte le coppie di D1 **e** di D2 (prese nell'ordine) # - **`D1.update(D2)`** modifica D1 # aggiungendo le coppie (K,V) di D2 nell'ordine # %% slideshow={"slide_type": "fragment"} editable=true # Esempi di operazioni sui dizionari D1 = { 1: 'uno', 2: 'due', 3:'tre' } D2 = { 11: 'undici', 2: 'ventidue', 33:'trentatre' } D = D1 | D2 # creo un dizionario con tutte le voci di D1 e D2 D # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Altre operazioni sui dizionari # - **`D.get(key, default)`** se la chiave è presente ne torna il valore, altrimenti torna il valore di default # - **`D.setdefault(key, default)`** se la chiave è presente ne torna il valore # altrimenti la inserisce col valore di default (e lo torna) # - **`D.pop(key, default)`** se la chiave è presente ne torna il valore e la rimuove, altrimenti torna il valore di default (o ERRORE se no default) # - **`D.fromkeys(keys, value)`** costruisce un dizionario con le chiavi fornite, tutte associate allo stesso valore indicato # %% slideshow={"slide_type": "fragment"} editable=true # Esempi di operazioni sui dizionari D.get(66, 'non trovato') # %% slideshow={"slide_type": "fragment"} editable=true dict.fromkeys('ABCADEF', 0) # %% slideshow={"slide_type": "fragment"} editable=true help(dict) # %% [markdown] slideshow={"slide_type": "slide"} editable=true # # Quesito con la Susi 2 # ![susi-2.png](susi-2.png) # # - un amico della Susi ha fatto un esame a crocette True/False con 100 domande # - le risposte giuste **True** erano tutte quelle **multiple di 3** e il resto **False** # - ma lui ha marcato **False** tutte le domande **multiple di 4** ed il resto **True** # # Quante ne ha azzeccate? # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # ## ancora problem-solving # - per contare quelle azzeccate # - scandisco i numeri da 1 a 100 e per ciascuno # - calcolo la risposta corretta # - calcolo la risposta data # - se sono uguali incremento il conteggio # - torno il conteggio # # (cosa manca? l'inizializzazione delle variabili!) # %% slideshow={"slide_type": "subslide"} editable=true # per contare le risposte giuste def conta_azzeccate(): # inizializzo una variabile per contare quelle azzeccate a 0 azzeccate = 0 # scandisco i numeri da 1 a 100 for i in range(1,101): # calcoliamo la risposta corretta corretta = risposta_corretta(i) # calcoliamo la risposta data data = risposta_data(i) # se la riposta data è uguale alla risposta corretta if corretta == data: # incremento il conteggio azzeccate += 1 # alla fine torno il conteggio return azzeccate # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - per calcolare la risposta corretta X-esima # - torno True se **X è multiplo di 3** # %% slideshow={"slide_type": "fragment"} editable=true # per calcolare la risposta corretta def risposta_corretta(X): # se il numero è divisibile per 3 # la risposta corretta è True # altrimenti # la risposta corretta è False return X%3 == 0 # %% [markdown] editable=true slideshow={"slide_type": "subslide"} # - per calcolare la risposta data X-esima # - torno True se **X NON è multiplo di 4** # %% slideshow={"slide_type": "subslide"} editable=true # per calcolare la risposta data def risposta_data(X): # se il numero è divisibile per 4 # lui ha risposto False # altrimenti # lui ha risposto True return X % 4 != 0 # Noooo Non vi do subito il risultato 3-) # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ## Un modo completamente diverso: con gli insiemi # - costruisco i due insiemi delle risposte **corrette_True** e **corrette_False** # - costruisco i due insiemi delle risposte **date_True** e **date_False** # - le risposte azzeccate sono: # - le **date_True** che sono **corrette_True** # - e le **date_False** che sono **corrette_False** # %% slideshow={"slide_type": "subslide"} editable=true # un altro modo di rispondere: con gli insiemi # raccolgo le risposte corrette # in due insiemi corrette_True e corrette_False domande = set(range(1,101)) # i numeri da 1 a 100 corrette_True = set(range(3,101,3)) # i multipli di 3 corrette_False= domande - corrette_True # i non multipli di 3 # raccolgo le risposte date True # in due insiemi date_True e date_False date_False = set(range(4,101,4)) date_True = domande - date_False # %% slideshow={"slide_type": "subslide"} editable=true # Le risposte giuste sono: # l'intersezione delle risposte date_False con le risposte corrette_False # assieme a # l'intersezione delle risposte date_True con le risposte corrette_True azzeccate = (corrette_True & date_True) | (corrette_False & date_False) # il risultato cercato è il numero di elementi dell'insieme # Noooo ... non ve lo dico, prima dovete risolverlo voi # %% [markdown] editable=true slideshow={"slide_type": "slide"} # ### Ma se invece degli insiemi usassimo dei dizionari **domanda->risposta** ? # - costruisco il dizionario **corrette** che contiene **domanda->risposta corretta** # - costruisco il dizionario **date** che contiene **domanda->risposta data** # - confronto i dizionari # %% editable=true slideshow={"slide_type": "subslide"} ## Un terzo modo usando i dizionari # costruisco i dizionari # numero -> risposta giusta # numero -> risposta data dizionario_risposte = {} for i in range(1, 101): dizionario_risposte[i] = i % 3 == 0 dizionario_date = {} for i in range(1, 101): dizionario_date[i] = i % 4 != 0 # %% editable=true slideshow={"slide_type": "subslide"} # e poi calcolo l'intersezione dei due insiemi di items (domanda, risposta) azzeccate_diz = set(dizionario_risposte.items()) & set(dizionario_date.items()) # La risposta dopo il break print(azzeccate) print(azzeccate_diz) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Wooclap: secondo voi quante risposte ha azzeccato ? # # ![wooclap.png](wooclap.png) # # %% slideshow={"slide_type": "fragment"} editable=true # vediamo finalmente quante ne ha azzeccate print('azzeccate', conta_azzeccate()) len(azzeccate) # %% [markdown] slideshow={"slide_type": "slide"} editable=true # # Ancora argomenti formali delle definizioni delle funzioni # # Avrete notato che la funzione **print** accetta un numero indefinito di argomenti # # Ma come fa? E' speciale? # # No, approfitta della sintassi degli **assegnamenti multipli** e del **packing/unpacking** # # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Assegnamento multiplo? (WTF?) # # **elenco di variabili = contenitore con stesso numero di elementi** # # Ciascuna variabile viene assegnata, **nell'ordine**, con i valori elencati a destra dell' **`=`** # # - **PRIMA** viene calcolato tutto il contenitore a destra # - **POI** viene fatto l'assegnamento # %% slideshow={"slide_type": "fragment"} editable=true A, B = 1, 2 A, B = B, A # fa uno SCAMBIO! print(A, B) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Ci permette di gestire facilmente gruppi di dati coerenti (struct o record in altri linguaggi) # %% slideshow={"slide_type": "fragment"} editable=true # p.es. se abbiamo altezza (H), larghezza (L) e profondità (P) # di una scatola in quest'ordine in una lista, dimensioni_scatola = [ 10, 20, 30, ] # per stamparli dovremmo prima estrarli H = dimensioni_scatola[0] L = dimensioni_scatola[1] P = dimensioni_scatola[2] # poi stamparli print('altezza',H) print('larghezza',L) print('profondità',P) # ma che strazio!!!! Bisogna ricordarsi gli indici! (0, 1, 2) # %% slideshow={"slide_type": "fragment"} editable=true # MOOOLTO meglio! H, L, P = dimensioni_scatola # li estraggo in ordine e li stampo print('altezza',H) print('larghezza',L) print('profondità',P) # NOTA: NON dobbiano ricordarci la posizione, # basta mettere le variabili nell'ordine giusto # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ## "packing" ed "unpacking" # # In un assegnamento possiamo raccogliere in una sola variabile tutti i valori rimanenti di una lista (**packing**) # # Il nome della variabile deve essere preceduto da asterisco **`*`** # # **NOTA** il packing avviene nelle variabili a SINISTRA di un assegnamento # %% slideshow={"slide_type": "fragment"} editable=true # PACKING: raccolgo in C tutti i valori # tranne i primi due che vanno in A e B # mettendo un asterisco subito prima del nome della variabile C A, B, *C = [ 1, 2, 3, 4, 5, 6] print('A:',A) print('B:',B) print('C:',C) # %% slideshow={"slide_type": "fragment"} editable=true # Esempio di packing che raccoglie *lista* vuota A, B, *C = (1,2) print('C ora è', C) # %% slideshow={"slide_type": "fragment"} editable=true # ancora meglio, posso mettere la variabile "packed" all'inizio!!! *A, B, C = [ 1, 2, 3, 4, 5, 6] print('A:',A) print('B:',B) print('C:',C) # %% slideshow={"slide_type": "fragment"} editable=true # oppure in mezzo!!! A, *B, C = [ 1, 2, 3, 4, 5, 6] print('A:',A) print('B:',B) print('C:',C) # %% [markdown] slideshow={"slide_type": "fragment"} editable=true # **Basta che ci sia una sola variabile "packed"
# in modo che Python sappia cosa mettere nelle altre,
così metterà il resto in quella con asterisco** # # %% slideshow={"slide_type": "subslide"} editable=true ## Quindi la definizione di print dev'essere simile a def my_print(*roba_da_stampare, end='\n', sep=' '): # roba_da_stampare è una *tupla* con tutti i valori passati # NOTA: print prima converte tutto in stringhe stringhe = [] for valore in roba_da_stampare: stringhe.append(str(valore)) # e poi stampa (qui uso print per semplicità) print(sep.join(stringhe), end=end) my_print(1, 1.3, [1, 2, 3]) # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### E l' "unpacking" cos'è? # # Sempre con l'asterisco possiamo "spacchettare" una variabile che contiene più valori all'interno di una altra **espressione** # ```python # X = sequenza # [ ..., *X, ... ] # diventa # [ ..., elementi di X, ... ] # ``` # **NOTA** l'unpacking avviene quando si **calcola** il valore della variabile # %% slideshow={"slide_type": "fragment"} editable=true # esempio di unpacking di un *set* X = {11, 22, 33, 44} D = 1, 2, *X, 4 # nella tupla appaiono gli elementi di X print('D ora è', D) # %% slideshow={"slide_type": "fragment"} editable=true # Esempio di unpacking di una sequenza di caratteri X = 'ABCDE' [ 1, 2, 3, 4, *X, 5, 6, 7, 8, ] # la espando in mezzo all'altra sequenza # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### RIASSUMENDO: se un asterisco precede il nome di una variabile: # - in un **assegnamento** fa il **packing** di zero o più valori in una **lista** # ( **tupla** se sono gli argomenti di una funzione) # - in una **espressione** fa l'**unpacking** dei valori contenuti nella variabile # %% [markdown] slideshow={"slide_type": "subslide"} editable=true # ### Wooclap: quanto vi è chiaro ? # # ![wooclap.png](wooclap.png) #