# ---
# 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]` ?
# 
# %% 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 ?
# 
# %% 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')