# --- # jupyter: # jupytext: # formats: ipynb,py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.14.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # %% [markdown] toc=true slideshow={"slide_type": "notes"} #

Table of Contents

#
# %% [markdown] slideshow={"slide_type": "slide"} # # Fondamenti di Programmazione # # # **Andrea Sterbini** # # lezione 3 - 10 ottobre 2022 # %% [markdown] slideshow={"slide_type": "slide"} # ## Ancora a proposito di stringhe # %% [markdown] slideshow={"slide_type": "subslide"} # Le **stringhe** `str` sono piu complesse di `int` e `float`.
# E' possibile pensarle codificate in memoria come `vettori` (sequenze di elementi uguali). # %% run_control={"marked": false} slideshow={"slide_type": "fragment"} nome = 'andrea sterbini' # %% [markdown] slideshow={"slide_type": "fragment"} # carattere | a | n | d | r | e | a | | s | t | e | r | b | i | n | i | # -- | -- | --| --| --| --| --| --| --| --| --| --| --| --| --| --| # indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| # # %% [markdown] slideshow={"slide_type": "fragment"} # 1. Si ottiene la lunghezza della sequenza di caratteri con `len(nome)` # %% [markdown] slideshow={"slide_type": "subslide"} # 2. E' possibile anche: # - indicizzare la stringa, ossia accedere **in maniera secca** (`random access`) a ciascun carattere # - l'indicizzazione avviene come se fosse un vettore # - per vedere il carattere quinto, non importa che chieda prima secondo, terzo e quarto. Accedo diretto al quinto `nome[4]` # %% [markdown] slideshow={"slide_type": "subslide"} # # 3. Molto importante!
**in informatica si inizia a contare da 0** # - `nome[0]` è il primo elemento # %% [markdown] slideshow={"slide_type": "subslide"} # carattere | a | n | d | r | e | a | | s | t | e | r | b | i | n | i | # -- | -- | --| --| --| --| --| --| --| --| --| --| --| --| --| --| # indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| # %% slideshow={"slide_type": "fragment"} nome[0] # %% slideshow={"slide_type": "fragment"} nome[100] #attenzione il mio nome e cognome non arriva a 100 caratteri # %% slideshow={"slide_type": "subslide"} len(nome) #infatti i caratteri sono 15 # %% cell_style="split" run_control={"marked": false} slideshow={"slide_type": "fragment"} # ok accediamo all quindicesimo nome[15] # %% [markdown] cell_style="split" slideshow={"slide_type": "fragment"} # # 😨 # %% [markdown] slideshow={"slide_type": "slide"} # carattere | a | n | d | r | e | a | | s | t | e | r | b | i | n | i | # -- | -- | --| --| --| --| --| --| --| --| --| --| --| --| --| --| # indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| # %% slideshow={"slide_type": "fragment"} start = nome[0] # accedo al primo elemento, lo metto dentro start end = nome[len(nome)-1] # calcolo la lunghezza della stringa. # ultimo elemento è in posizione luneghezza-1. Ci accedo # lo metto dentro end print(start) #stampa la prima lettera print(end) #stampa l'ultima lettera # %% slideshow={"slide_type": "fragment"} # Posso invece contare dalla fine ultimo = nome[-1] penultimo = nome[-2] print(ultimo) print(penultimo) # %% cell_style="split" slideshow={"slide_type": "subslide"} # possiamo anche "affettare" la stringa # per estrarre il mio nome (slicing) nome[0:6] # da notare MOLTO IMPORTANTE # 0 e' compreso, 6 escluso # %% [markdown] cell_style="split" slideshow={"slide_type": "fragment"} # car.| a | n | d | r | e | a | # ----|---|---|---|---|---|---| # idx | 0 | 1 | 2 | 3 | 4 | 5 | # %% [markdown] slideshow={"slide_type": "slide"} # Assumiamo di volere estrarre `drea`
da `andrea sterbini`. # - Come facciamo? # - Ricordiamoci che il carattere spazio nel mezzo **e'** un carattere (lo spazio si codifica nel computer) # %% [markdown] slideshow={"slide_type": "fragment"} # carattere | a | n | d | r | e | a | | s | t | e | r | b | i | n | i | # -- | -- | --| --| --| --| --| --| --| --| --| --| --| --| --| --| # indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| # %% [markdown] slideshow={"slide_type": "fragment"} # - Possiamo fare slicing con l'operatore **`:`** da 2 a 6 ossia **`[2:6]`** (prendi la fetta che va dall'indice 2 al 6 escluso) # %% [markdown] slideshow={"slide_type": "subslide"} # - Ricordatevi `gli indici di slicing` in python sono sempre $[\text{ start},\text{end })$ # - `start` incluso, `end` **ESCLUSO** # %% slideshow={"slide_type": "fragment"} sub_name = nome[2:6] print(sub_name) # %% [markdown] slideshow={"slide_type": "subslide"} # E se non sappiamo dove inizia `drea`, che facciamo? # - Sappiamo che dobbiamo cercare `drea` # - `drea` è lungo 4 caratteri, ma possiamo usare il metodo `len()` per calcolarsi la lunghezza della stringa, cosi funzionerà con tutte le stringhe, non solo con `drea`. # - Come facciamo a trovare l'indice di inizio di `drea` dentro `nome`? # %% [markdown] slideshow={"slide_type": "fragment"} # > Se ci fate caso ci stiamo piano piano approcciando al **problem solving** # %% slideshow={"slide_type": "subslide"} help(str) # conviene leggersi le funzionalita' del tipo str # %% [markdown] slideshow={"slide_type": "subslide"} # ``` # | index(...) # | S.index(sub[, start[, end]]) -> int # | # | Return the lowest index in S where substring sub is found, # | such that sub is contained within S[start:end]. Optional # | arguments start and end are interpreted as in slice notation. # | # | Raises ValueError when the substring is not found. # ``` # %% [markdown] slideshow={"slide_type": "subslide"} # **`S.index(sottostringa) -> int`** # # 1. prendo la stringa `S` ci applico la funzionalita' `index` che prende `sottostringa` come argomento # 2. Rende un intero `-> int` che indica la posizione trovata (oppure -1 se non c'è) # 3. Questa e' documentazione non codice # %% slideshow={"slide_type": "subslide"} # quindi possiamo fare # nome vale 'andrea sterbini ' start = nome.index('drea') start # %% slideshow={"slide_type": "fragment"} nome[start:start+len('drea')] # [2,2+4) # %% [markdown] slideshow={"slide_type": "fragment"} # **d** | **r** | **e** | **a** | # ---- | -- | -- | -- | # **2** | **3** | **4** | **5** | # # %% slideshow={"slide_type": "fragment"} # mettendo tutto insieme query = 'drea' # input dell'algoritmo start = nome.index(query) # trovo il primo indice che contiene il contenut di QUERY # sulla contenuto di NOME end = start + len(query) # mi precalcolo indice di fine stringa sub_name = nome[start:end] # faccio slicing della stringa print(sub_name,start,end,nome) # stampo cosa ho trovato e dove, a partire da cosa # %% [markdown] slideshow={"slide_type": "fragment"} # **d** | **r** | **e** | **a** | # ---- | -- | -- | -- | # **2** | **3** | **4** | **5** | # # %% [markdown] slideshow={"slide_type": "slide"} # ### Di più su slicing # %% [markdown] slideshow={"slide_type": "slide"} # - E' possibile anche **non mettere il valore di start e end** # - E' possibile andare **al contrario** # - E' possibile **saltare ogni K elementi** # %% cell_style="split" slideshow={"slide_type": "fragment"} nome[1:] # tutti i caratteri DOPO il # primo (0 escluso, 1 compreso) # 0 | 1----------------- # %% cell_style="split" run_control={"marked": false} slideshow={"slide_type": "fragment"} nome[:2] # tutti i caratteri PRIMA # del indice 2 escluso # quindi solo carattere 0-th # --0--1--| 2 3 4 5 6 7... # %% slideshow={"slide_type": "subslide"} nome[-1] # al contrario di molti linguaggio a basso livello # qui gli indici possono essere negativi # il meno inverte la sequenza di lettura # sto prendendo da 'andrea sterbini' <--- questa i finale # %% [markdown] slideshow={"slide_type": "fragment"} # - Questa complessità è molto utile e efficace ma ovviamente **va saputa gestire** # - Molto facile ingarbugarsi su `slicing` complessi perchè notazione è macchinosa (imho) # %% [markdown] slideshow={"slide_type": "subslide"} #
# %% slideshow={"slide_type": "fragment"} nome = 'Python' vuoto = nome[4:3] # ovviamente se start >= end, abbiamo stringa vuota type(vuoto),vuoto # %% slideshow={"slide_type": "fragment"} nome = 'Python' vuoto = nome[-3:-4] # ovviamente se start >= end, abbiamo stringa vuota '' type(vuoto),vuoto # %% slideshow={"slide_type": "fragment"} nome = 'Python' nome[-4:-3] == nome[2:3], nome[2:3] # questo funzione seleziona il carattere 't' (un singolo carattere e' una stringa) # %% [markdown] slideshow={"slide_type": "subslide"} #
# %% slideshow={"slide_type": "fragment"} nome = 'Python' nome[-10:2], nome[3:100] # se l'inizio è negativo e troppo grande si inizia dal primo carattere # se la fine della slice è troppo grande si arriva all'ultimo # %% slideshow={"slide_type": "fragment"} nome[-1000] # MA ATTENZIONE: se invece indicizziamo il singolo carattere # non possiamo chiedere più di -(len(nome)-1) # %% slideshow={"slide_type": "subslide"} # Prendiamo tutti i caratteri in posizione multipla di 3 # il terzo valore indica come incrementare l'indice nome[::3] # %% # prendiamoli in direzione opposta (incremento negativo) nome[::-1] # %% [markdown] slideshow={"slide_type": "slide"} # ## Momento Wooclap # #### quanto fa: `'ippopotamo'[2:-2:2]` ?
e invece `'BabbuINO'.lower()[-1:-10:-3]` ? # ![wooclap.png](wooclap.png) # %% slideshow={"slide_type": "slide"} # Risultati 'ippopotamo'[2:-2:2], 'BabbuINO'.lower()[-1:-10:-3] # %% [markdown] slideshow={"slide_type": "slide"} # ## Stringhe come Tipo Immutabile # %% [markdown] slideshow={"slide_type": "fragment"} # - I tipi **mutabili e immutabili** in python li vediamo meglio nelle prossime lezioni # - Informalmente, un tipo **immutabile** vuol dire che una volta che e' stato creato **NON** può essere più modificato # - Per chi viene dal `C` questa cosa non e' molto chiara perchè in C potete modificare direttamente le stringhe carattere per carattere # %% slideshow={"slide_type": "subslide"} nome = 'Python' # %% [markdown] slideshow={"slide_type": "fragment"} # assumiamo io voglia modificare la `P` di `Python` in minuscola `python` # %% slideshow={"slide_type": "fragment"} # in C potrei fare nome[0] = 'p' # %% [markdown] slideshow={"slide_type": "subslide"} # In realta' non lo posso fare direttamente,
devo per forza creare un'altra stringa # %% cell_style="split" slideshow={"slide_type": "fragment"} A = nome.lower() # trasformo tutto in minnuscole A # %% cell_style="split" slideshow={"slide_type": "fragment"} B = 'p'+nome[1:] # oppure faccio cut/paste B # %% slideshow={"slide_type": "fragment"} # con id(oggetto) posso capire se due cose sono lo stesso oggetto id(A), id(B), id(A)==id(B) # le due stringhe sono in posti diversi della memoria ? # %% slideshow={"slide_type": "subslide"} help(id) # %% [markdown] slideshow={"slide_type": "slide"} # ### String Literals # Se dobbiamo scrivere testi che contengono accapi ('\n') possiamo usare il triplo apice **`'''`** oppure il triplo doppio apice **`"""`** # %% slideshow={"slide_type": "fragment"} print(""" Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to """) # %% [markdown] slideshow={"slide_type": "slide"} # ### String interpolation # Possiamo costruire facilmente dei testi che contengono valori calcolati (ad es. presi da variabili) # %% [markdown] slideshow={"slide_type": "fragment"} # - precedendo la stringa con la lettera **`f`** (che sta per 'formatted') # - inserendo i valori da interpolare tra parentesi graffe **`{espressione}`** # - se vogliamo, indicando come visualizzare il dato interpolato (vedi documentazione) # %% slideshow={"slide_type": "subslide"} # definiamo le parti da interpolare nel testo nome = 'Paolino' cognome = 'Paperino' indirizzo = 'Via dei Peri 32' data = '29 febbraio' orario = '20:30' mittente = 'Gastone Paperone' # %% slideshow={"slide_type": "subslide"} # e la lettera da spedire (che interpola semplici variabili) lettera = f''' Caro {nome} {cognome} La invito al vernissage che si terrà a {indirizzo} il giorno {data} alle ore {orario} Cordialmente {mittente} ''' # %% slideshow={"slide_type": "fragment"} print(lettera) # %% [markdown] slideshow={"slide_type": "slide"} # ## Variabili e riferimenti # %% slideshow={"slide_type": "skip"} from graphviz import Digraph # Create Digraph object figura = Digraph() figura.body.append(''' graph [rankdir=LR] node [shape=rect] "namespace containing\n the variable (name)\nA" -> "RAM containing\n a reference to object" -> "RAM containing\n the object data" ''') # %% slideshow={"slide_type": "fragment"} figura ## Ogni variabile è un nome contenuto in una tabella (namespace) ## che contiene un 'riferimento' all'oggetto in essa contenuto # %% [markdown] slideshow={"slide_type": "slide"} # ## Uguaglianza ed identità # %% [markdown] slideshow={"slide_type": "fragment"} # Due oggetti possono essere abbastanza simili (se sono dello stesso tipo e contengono le stesse informazioni, sono interscambiabili) # # Il confronto **==** torna True (uguaglianza dei contenuti) # # Ma possono trovarsi in due aree di memoria diverse e quindi essere oggetti diversi # (modificandone uno l'altro resta invariato) # %% [markdown] slideshow={"slide_type": "subslide"} # Per distinguerli e sapere in qualche modo dove sono in memoria si usa la funzione **id** # e per controllare se sono 'identici' si usa l'operatore **is** (identità) # %% slideshow={"slide_type": "fragment"} # creiamo una stringa e copiamo la variabile A in B A = 'Pippo e Pluto sono andati al mare con Minnie e Topolino' B = A # Se hanno lo stesso ID, di tratta dello stesso oggetto print(id(A)) print(id(B)) A is B # %% slideshow={"slide_type": "skip"} from graphviz import Digraph def show_vars( *variabili ): grafo = Digraph() grafo.body.append(f''' graph [rankdir=LR] node [shape=rect]''') for nome in variabili: valore = eval(nome) grafo.body.append(f''' {nome} -> "{id(valore)}" -> "{valore}" ''') return grafo # %% slideshow={"slide_type": "subslide"} show_vars( 'A', 'B' ) # %% [markdown] slideshow={"slide_type": "slide"} # ## Le variabili sono i nomi che diamo a luoghi nella memoria # e contengono un riferimento (indirizzo) dell'oggetto in memoria # - possiamo **modificare le info contenute in un oggetto** 'riferito' da una variabile # - oppure **sostituire** nella variabile **il riferimento** ad un altro oggetto
# L'operazione di assegnamento CAMBIA IL RIFERIMENTO contenuto nella variabile # %% slideshow={"slide_type": "subslide"} # esempio: assegnamento che cambia il riferimento A = 78 A_prima = A A = 'paperino' A_dopo = A print(id(A_prima)) print(id(A_dopo)) # %% slideshow={"slide_type": "fragment"} show_vars('A_prima') # %% slideshow={"slide_type": "fragment"} show_vars('A_dopo') # %% slideshow={"slide_type": "subslide"} # Esempio di un contenitore: una lista di oggetti eterogenei L = [1, 'due', 3.5] # ne copio il riferimento in una seconda variabile M = L # sono proprio la stessa cosa print(id(L),id(M), L is M) # %% slideshow={"slide_type": "fragment"} show_vars('M', 'L') # %% slideshow={"slide_type": "subslide"} # modifico il contenuto a posizione 1 (secondo elemento, si conta da 0) L[1] = 42 # si tratta sempre dello stesso oggetto sia in L che in M print('identici?', L is M, '\nuguali?', L == M) # ed è stato modificato il secondo elemento print(L, M) # %% slideshow={"slide_type": "fragment"} show_vars('M', 'L') # %% slideshow={"slide_type": "subslide"} # ma se creo una lista con gli stessi dati L = [1, 42, 3.5] print('identici?', L is M, '\nuguali?', L == M) show_vars('M') # %% slideshow={"slide_type": "fragment"} show_vars('L') # %% [markdown] slideshow={"slide_type": "slide"} # # Tutti i dati in Python sono "oggetti" # # - un oggetto è un **gruppo di informazioni coerenti** (`attributi`)
# Es. cane: nome, altezza, razza, peso, colore, ...
# Es. str: lunghezza, sequenza di caratteri, ...
# %% [markdown] slideshow={"slide_type": "fragment"} # - con tutte le **operazioni che potete eseguire** (`metodi`)
# Es. cane: abbaia, scodinzola, cammina, corre, salta
# Es. str: join, split, upper, lower, startswith, ... # %% [markdown] slideshow={"slide_type": "subslide"} # int, str, bool, float, etc... sono oggetti
# per scoprirne le caratteristiche usiamo help oppure ctrl-I in Spyder oppure . e l'autocompletamento # %% slideshow={"slide_type": "fragment"} str # testo int # interi # abs, mod, %, // float # numeri con virgola complex # numeri complessi # conjugate, imag, real, ... bool # booleani (True, False)# and, or, not from fractions import Fraction # frazioni intere #help(Fraction) f = Fraction(124,14) # denominator, numerator f # %% [markdown] slideshow={"slide_type": "slide"} # ## I metodi sono le operazioni che possiamo compiere su un oggetto # e che ne possono manipolare il contenuto o crearne di nuovi # # Es. le operazioni su str
# - join, split, lower, upper, find, ... # %% [markdown] slideshow={"slide_type": "subslide"} # ## Per eseguire un metodo di un oggetto # si usa la sintassi **`oggetto.nomedelmetodo(argomenti)`** # # %% slideshow={"slide_type": "fragment"} # Esempi S = 'Paperino andò\t al, mare\n a nuotare' # split (e varianti) L = S.split() # join '|'.join(L) S.lower() # islower, isupper, isalpha, isnumeric S.islower() # upper, lower, title S.upper() # find S.find('mare') # %% [markdown] slideshow={"slide_type": "subslide"} # **NOTA:** le **stringhe sono IMMUTABILI**, ogni volta che ci fate operazioni sopra ne create una nuova # %% [markdown] slideshow={"slide_type": "fragment"} # ### NOTA: per rendere più efficiente l'uso della memoria # Python, invece che duplicarle, tiene copie uniche dei **numeri piccoli** e delle **stringhe corte** # %% slideshow={"slide_type": "fragment"} B = 93 C = 92+1 print(id(B), id(C)) B is C # %% slideshow={"slide_type": "subslide"} # per le stringhe l'ottimizzazione è applicata alle 'parole' # che non contengono spazi (particolarmente importante nella # ottimizzazione del codice in memoria) S1 = 'giovanni' * 50 S2 = 'giovanni' * 50 print(id(S1), id(S2)) S1 is S2 # %% slideshow={"slide_type": "subslide"} # esempio di ottimizzazione dei piccoli numeri esponente = 2 print((34**esponente) == ((30+4)**esponente), 'uguaglianza') print((34**esponente) is ((30+4)**esponente), 'identità') # %% [markdown] slideshow={"slide_type": "skip"} # # Modello dei dati di Python # ### DUCK typing: "se cammina come una papera e fa 'quack' come una papera, allora è una papera" # Nel *modello dei dati* del Python vogliamo che due oggetti siano intercambiabili quando 'si comportano allo stesso modo' # %% [markdown] slideshow={"slide_type": "skip"} # **'si comportano allo stesso modo' == 'hanno gli stessi metodi'** # # (MA NOTATE: metodi con nomi uguali potrebbero avere realizzazioni interne diverse) # # E' quindi possibile costruire nuovi tipi di oggetti che si comportano # in modo simile ad altri # # i numeri interi e i float sono un esempio (e anche i razionali e i complessi) # # (vedremo in seguito come farlo) # %% [markdown] slideshow={"slide_type": "slide"} # ## NOTA: incapsulamento delle informazioni # gli attributi (informazioni interne) degli oggetti in Python NON sono protetti # # In altri linguaggi compilati (Java, C++) **è possibile 'nascondere'** le informazioni interne # e fare in modo che solo i metodi dell'oggetto le possano manipolare # # In Python (interpretato) questo non è possibile (o è stato scelto così) # %% [markdown] slideshow={"slide_type": "slide"} # Ma si è stabilito che per convenzione # # **TUTTI GLI ATTRIBUTI E METODI CHE INIZIANO CON '_' SONO PRIVATI** # # e **non vanno letti o modificati o usati direttamente** # # (chi li ha inventati potrebbe benissimo modificarli in future versioni del programma) # # quindi **NON USATE MAI** i metodi speciali :-) # # (vedremo poi come definirli) # %% [markdown] slideshow={"slide_type": "subslide"} # Esistono alcuni **metodi speciali** (che iniziano per **`__`** ) che realizzano le funzionalità degli operatori # usati nelle espressioni/istruzioni. Per es. # - **`__eq__`** che implementa l'operatore **`==`** # - **`__add__`** che implementa l'operatore **`+`** # - **`__mul__`** che implementa l'operatore **`*`** # - **`__len__`** che implementa la funzione **`len`** # # Tutti gli oggetti che implementano questi metodi possono essere confrontati, sommati, moltiplicati, contati, ... # %% [markdown] slideshow={"slide_type": "subslide"} # Ecco come mai le stringhe possono essere sommate o moltiplicate, hanno un proprio metodo **`__add__`** e **`__mul__`** # # Questo vi sarà utile quando vedremo come costruire oggetti che possiamo confrontare # sommare, o di cui vogliamo calcolare la lunghezza (se contengono elementi) ... # %% slideshow={"slide_type": "fragment"} N = 3 N.__add__(5) # questo è cosa succede veramente se scrivo N + 5 # %% slideshow={"slide_type": "fragment"} # i numeri complessi hanno le 4 operazioni come gli altri numeri # (ma sono implementate diversamente) X_complesso = 3 + 2j # si usa j al posto di i=sqrt(-1) Y_complesso = 7 - 6j Z_complesso = X_complesso + Y_complesso # somma complessa Z_complesso, Z_complesso.real, Z_complesso.imag # %% [markdown] slideshow={"slide_type": "slide"} # # Funzioni: come definire parti di programma riusabili # # - **MAI:** copiare e incollare più volte lo stesso pezzo di codice # - **SEMPRE:** definisci una funzione separata e chiamala quante volte vuoi # %% [markdown] slideshow={"slide_type": "subslide"} # ### Sintassi: (come si scrive) # ```python # def nome_della_funzione( argomenti ): # 'docstring che descrive cosa fa' # istruzioni che calcolano il risultato # return risultato # ``` # # Il corpo della funzione DEVE essere indentato (in genere di 4 spazi) # %% [markdown] slideshow={"slide_type": "fragment"} # Gli `argomenti` sono nomi che **indicano le informazioni necessarie** perchè la funzione possa svolgere il suo compito # # **NOTA:** i nomi degli argomenti sono variabili disponibili SOLO nel corpo della funzione (la parte indentata) # # Il `risultato` è il dato che la funzione ha calcolato e che viene fornito al programma che la usa # %% [markdown] slideshow={"slide_type": "slide"} # ### ESEMPIO: calcolare l'altezza media di un gruppo # %% slideshow={"slide_type": "fragment"} # come si definisce la funzione def media_altezze(altezze): 'calcolo la media di un gruppo di altezze' # docstring somma_altezze = sum(altezze) media_altezze = somma_altezze/len(altezze) return media_altezze # valore risultante # %% slideshow={"slide_type": "fragment"} ## Come la si usa/chiama la funzione # se abbiamo una lista di altezze elenco_altezze = [ 170, 190, 165, 155, 186, 172, ] # e ne calcoliamo la media chiamando la funzione 'media_altezze' media = media_altezze(elenco_altezze) # e mettendo il risultato in una variabile # otteniamo media # %% [markdown] slideshow={"slide_type": "subslide"} # ### NOTATE CHE # - i nomi che ho usato nella **definizione** della funzione sono `altezze` (**parametri formali**, i dati che la funzione riceve da chi la chiama) # - i nomi che ho usato nel codice che USA la funzione sono `elenco_altezze` # (**parametri attuali**, i dati che effettivamente voglio fornire a questa particolare chiamata della funzione) # # **Stile:** è meglio usare nomi diversi per i parametri **formali** e per gli **attuali** per evitare di confondersi # %% [markdown] slideshow={"slide_type": "subslide"} # ### Ancora questioni di stile: identificatori **parlanti** # - scegliete sempre un **nome di funzione** che vi ricorda bene **cosa fa** # - GOOD: `calcola_altezza_media` # - BAD: `pippo` # %% [markdown] slideshow={"slide_type": "fragment"} # - scegliete sempre i **nomi degli argomenti** in modo che sia chiaro **quali informazioni dovete fornire** alla funzione # - GOOD: `altezze` # - BAD: `lista` # %% [markdown] slideshow={"slide_type": "subslide"} # - scegliete sempre i **nomi delle variabili** in modo che vi sia chiaro **cosa contengono** # - GOOD: `somma_altezze` # - BAD: `sa` # %% [markdown] slideshow={"slide_type": "slide"} # ## Namespaces: dove stanno i nomi delle variabili e funzioni # # # - **`globale`**: è il livello più esterno del vostro programma, in cui scrivete le istruzioni direttamente appoggiate al bordo sinistro # - variabili globali: accessibili dentro a tutte le funzioni e metodi (ALTAMENTE SCONSIGLIATE perchè creano errori difficili da trovare) # - funzioni globali: accessibili a tutte le altre funzioni del file # %% [markdown] slideshow={"slide_type": "subslide"} # - **`modulo`**: è il contenuto di un file importato con `import`, ci trovate le variabili e le funzioni definite in quel file. Le ottenete scrivendo **`modulo.variabile`** oppure **`modulo.funzione(argomenti)`** # - **`locale`**: ogni funzione usa delle variabili proprie, dette variabili **locali**, che sono accessibili SOLO nelle istruzioni del corpo # della funzione o di una sua sottofunzione. Gli **argomenti** della funzione sono anche loro variabili locali alla funzione. # # **ATTENZIONE** una variabile locale può *nascondere* una variabile globale # %% slideshow={"slide_type": "subslide"} variabile = 42 # definisco una variabile globale def funzione_di_prova( argomento ): variabile = argomento # qui la ridefinisco come locale print(variabile, 'stampo la locale') print(variabile, 'globale') funzione_di_prova(92) print(variabile, 'globale invariata') funzione_di_prova(667) # %% [markdown] slideshow={"slide_type": "slide"} # ## Chiamata delle funzioni e
vita delle variabili locali # Le variabili locali ad una funzione vengono **CREATE** nel momento in cui la funzione viene **ESEGUITA** (e non quando viene definita) # # Ogni esecuzione crea un **nuovo gruppo di variabili locali** della funzione # # Per cui le funzioni possono richiamare se stesse senza problemi, **ciascuna chiamata userà uno spazio di memoria personale** separato dagli spazi delle altre chiamate # %% [markdown] slideshow={"slide_type": "subslide"} # Le **variabili locali** sono **rilasciate quando si esce
dalla funzione** e si torna al programma che l'ha chiamata # # **NOTA:** la memoria che viene **rilasciata** è quella dei RIFERIMENTI.
Gli oggetti creati dalla funzione possono sopravviverle # # MA QUESTO FA SPRECARE UN SACCO DI MEMORIA ??? # # NO, esiste un processo in background, il **garbage collector** che esamina la memoria continuamente e libera tutti gli oggetti che **non sono più raggiungibili** dai programmi in esecuzione # %% slideshow={"slide_type": "subslide"} ## Esempio di creazione di un oggetto dentro una funzione def concatena(prima_parte, seguito): # costruisco una nuova stringa nuovo_testo = prima_parte + ' ' + seguito return nuovo_testo # e la ritorno A = 'inizio ' B = 'fine' C = concatena(A, B) print(A, B, C, sep='\n') print(prima_parte) # errore perchè 'nuovo_testo' non esiste nel namespace globale # %% [markdown] slideshow={"slide_type": "slide"} # ## Ancora booleani: come scegliere
alternative diverse # # - gli operatori di confronto sono le espressioni booleane più semplici # - potete combinarli con gli operatori **`and`**, **`or`** e **`not`** # - **`not`** ha priorità su **`and`** che l'ha su **`or`** # - usate le parentesi altrimenti # # E' quindi possibile scrivere condizioni complesse # ```python # piove = not soleggiato or strade_bagnate # porto_l_ombrello = piove or sole_abbacinante # strade_bagnate = ha_piovuto or innaffiamento_automatico_acceso # ``` # # %% [markdown] slideshow={"slide_type": "slide"} # ## Condizioni e percorsi alternativi # # Per scegliere parti diverse di codice si usa l'istruzione **`if`** e delle condizioni (booleane) che valgono **True** o **False** # # **Sintassi:** # ```python # if condizione1: # istruzioni eseguite # se condizione1 è True # elif condizione2: # opzionale # istruzioni eseguite # se condizione1 è False e condizione2 è True # else: # opzionale # istruzioni eseguite # se condizione1 e condizione2 sono False # ``` # %% [markdown] slideshow={"slide_type": "slide"} # ## Momento Wooclap # #### Quanto valgono queste espressioni booleane ? # #### Cosa stampa il programma ? # ![wooclap.png](wooclap.png) # %% slideshow={"slide_type": "subslide"} ## Soluzioni True and not False or True and False or not True # è lo stesso che scrivere (True and (not False) ) or (True and False) or (not True) # cioè (True and True) or False or False # %% slideshow={"slide_type": "fragment"} # Visto che True == 1 e che False == 0 True+False/True+True*True-False # è lo stesso che 1 + 0 / 1 + 1 * 1 - 0 # %% slideshow={"slide_type": "subslide"} # soluzione 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')