<jupyter_start><jupyter_text>Introduzione rapida a Python [Scarica zip esercizi](../_static/generated/quick-intro.zip)[Naviga file online](https://github.com/DavidLeoni/softpython-it/tree/master/quick-intro)**REQUISITI:**    * **QUESTO FOGLIO E' PER CHI HA GIA' COMPETENZE DI PROGRAMMAZIONE**, e in 3-4h vuole farsi rapidamente un'idea di Python* **Aver installati Python 3 e Jupyter:** se non hai già provveduto, guarda [Installazione](https://it.softpython.org/installation.html)    **SE SEI UN PRINCIPIANTE**: Salta questo foglio e fai invece i tutorial che trovi nella sezione [Fondamenti](https://it.softpython.org/index.htmlA---Fondamenti), a partire da [Strumenti e script](https://it.softpython.org/tools/tools-sol.html)  Che fare- scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere: ```quick-intro    quick-intro.ipynb         quick-intro-sol.ipynb         jupman.py         ```**ATTENZIONE**: Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.**ATTENZIONE**: In questo libro usiamo **SOLO PYTHON 3** Se per caso ottieni comportamenti inattesi, controlla di usare Python 3 e non il 2. Se per caso il tuo sistema operativo scrivendo `python` fa partire il 2, prova ad eseguire il tre scrivendo il comando: `python3`- apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook `quick-intro.ipynb`- Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte **ESERCIZIO**, che ti chiederanno di scrivere dei comandi Python nelle celle successive. Gli esercizi sono graduati per difficoltà, da una stellina ✪ a quattro ✪✪✪✪**ATTENZIONE**: Ricordati di eseguire sempre la prima cella dentro il notebook. Contiene delle istruzioni come `import jupman` che dicono a Python quali moduli servono e dove trovarli. Per eseguirla, vedi le seguenti scorciatoieScorciatoie da tastiera:* Per eseguire il codice Python dentro una cella di Jupyter, premi `Control+Invio`* Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi `Shift+Invio`* Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi `Alt+Invio`* Se per caso il Notebook sembra inchiodato, prova a selezionare `Kernel -> Restart`  Proviamo JupyterVediamo brevemente come funzionano i fogli Jupyter.  **ESERCIZIO**: Proviamo a inserire un comando Python: scrivi nella cella qua sotto `3 + 5`, e poi mentre sei in quella cella premi i tasti speciali `Control+Invio`. Come risultato, dovresti vedere apparire il numero 8 **ESERCIZIO**: in Python possiamo scrivere commenti iniziando una riga con un cancelletto ``. Come prima, scrivi nella cella sotto `3 + 5` ma questa volta scrivilo nella riga sotto la scritta ` scrivi qui`:<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**ESERCIZIO**: Jupyter per ogni cella mostra il risultato solo dell'ultima riga eseguita in quella cella. Prova a inserire questo codice nella cella sotto ed esegui premendo `Control+Invio`. Che risultato appare?```python3 + 51 + 1```<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**ESERCIZIO**: Proviamo adesso a creare noi una nuova cella. * Mentre sei con il cursore in questa cella, premi `Alt+Invio`. Si dovrebbe creare una nuova cella dopo la presente. * Nella cella appena creata, inserisci `2 + 3` e poi premi `Shift+Invio`. Cosa succede al cursore? prova la differenze con `Control+Invio`. Se non capisci la differenza, prova a premere ripetutamente `Shif+Invio` e vedi che succede.    Principali tipi di dati PythonDato che il tema del corso è il trattamento dei dati, per cominciare ci focalizzeremo sui tipi di dati in Python. **Riferimenti**: - [Pensare in Python, Capitolo 1, Lo scopo del programma](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2002.html) - [Pensare in Python, Capitolo 2, Variabili, istruzioni ed espressioni](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2003.html)Quando leggiamo delle informazioni da una fonte esterna come un file, poi dovremo inevitabilmente incastonare i dati letti in qualche combinazione di questi tipi: | Tipo | Esempio 1 | Esempio 2 | Esempio 3||--------|-----|---|----||int|  `0`|`3`| `-5`||numero in virgola mobile float| `0.0`| `3.7` | `-2.3`| |bool|False|True|||string  |`""`| `"Buon giorno"`|`'come stai?'`||list | `[]`|`[5, 8, 10]`|[`"qualcosa", 5, "altro ancora"]`|| dict |`{}`|`{'chiave 1':'valore 1', 'chiave 2':'valore 2'}`|`{5:'un valore stringa', 'chiave stringa':7}`| A volte, useremo tipi più complessi, per esempio i valori temporali si potrebbero mettere in oggetti di tipo `datetime` che oltre alla data vera e propria possono contenere anche il fuso orario.In quel che segue, forniremo alcuni esempi rapidi su quello che si può fare sui vari tipi di dato, mettendo i riferimenti alle spiegazioni più dettagliate dal libro Pensare in Python.   Numeri interi e con virgolaNel libro 'Pensare in Python' non c'è un vero e proprio capitolo dedicato ai calcoli numerici, che sono sparse nei primi capitoli segnalati prima. Metto qua due note velocissime:In Python abbiamo numeri interi:<jupyter_code>3 + 5<jupyter_output><empty_output><jupyter_text>La somma tra interi ovviamente ci da un intero:<jupyter_code>type(8)<jupyter_output><empty_output><jupyter_text>E se dividiamo interi? Ci troveremo con il tipo in virgola mobile _float_:<jupyter_code>3 / 4
type(0.75)<jupyter_output><empty_output><jupyter_text>**ATTENZIONE al punto !**In Python e in molti formati dati, al posto della nostra virgola si usa il formato inglese con il punto '.'  **✪ ESERCIZIO**: Prova a scrivere qua sotto `3.14` con il punto, e poi `3,14` con la virgola  ed esegui con Ctrl+Invio. Cosa appare nei due casi?<jupyter_code># scrivi qui con il punto


# scrivi qui con la virgola<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Prova a scrivere qua sotto `3 + 1.0` ed esegui con Ctrl+Invio. Di quale tipo sarà il risultato? Controlla anche usando il comando `type`.<jupyter_code># scrivi qui i comandi<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Qualche professore di matematica ti avrà sicuramente intimato di non dividere mai per zero. Neanche a Python piace molto, prova a scrivere nella cella qua sotto `1 / 0` e poi premi Ctrl+Invio per eseguire la cella. Nota come Python riporterà la riga dove è accaduto l'errore:<jupyter_code># scrivi qui sotto il codice<jupyter_output><empty_output><jupyter_text>Booleani - boolI booleani rappresentano valori veri e falsi, e si possono usare per verificare quando certe condizioni avvengono.                                                                      **Riferimenti*** Softpython: [Basi - booleani](https://it.softpython.org/basics/basics-sol.htmlBooleani)- Softpython: [controllo di flusso - if](https://it.softpython.org/control-flow/flow1-if-sol.html) Per indicare i booleani Python ci fornisce due costanti `True` e `False`. Cosa ci possiamo fare? andPotremmo usarle per segnare in variabili se un certo fatto è avvenuto, per esempio possiamo fare un programma che al mattino ci dice che possiamo uscire di casa solo dopo aver fatto entrambe (`and`) colazione e e lavato i denti:<jupyter_code>fatto_colazione = True
lavato_denti = True

if fatto_colazione and lavato_denti:
    print("fatto tutto !")
    print("posso uscire di casa")
else:
    print("NON posso uscire di casa")<jupyter_output>fatto tutto !
posso uscire di casa<jupyter_text>**✪ ESERCIZIO**: prova a scrivere qui sotto a mano il programma riportato nella cella precedente, ed eseguilo con Control+Invio. Prova a cambiare i valori da `True` a `False` e guarda che succede. Assicurati di provare tutti i casi:- True True- True False- False True- False False**ATTENZIONE**: Ricordati i `:` alla fine della riga con `if` !!!!<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>Si può anche mettere un `if` dentro l'altro (_nested if_). Per esempio, questo programma qui funziona esattamente come il precedente:<jupyter_code>fatto_colazione = True
lavato_denti = True

if fatto_colazione:
    if lavato_denti:                        # NOTA: Questo blocco if è indentato rispetto
        print("fatto tutto !")              #       all' if fatto_colazione
        print("posso uscire di casa!")      #
    else:
        print("NON posso uscire di casa")
else:
    print("NON posso uscire di casa")<jupyter_output>fatto tutto !
posso uscire di casa!<jupyter_text>**✪ ESERCIZIO**: Prova a modificare il programma riportato nella cella precedente per fargli riportare lo stato delle varie azioni compiute. Elenchiamo qui i possibili casi e i risultati attesi:- True False```ho fatto colazionenon ho lavato i dentiNON posso uscire di casa```- False True- False False```non ho fatto colazioneNON posso uscire di casa```- True True```ho fatto colazioneho lavato i dentifatto tutto !posso uscire di casa!```<jupyter_code># scrivi qui

fatto_colazione = True
lavato_denti = True

if fatto_colazione:
    print("ho fatto colazione")
    
    if lavato_denti:                        # NOTA: Questo blocco if è indentato rispetto
        print("ho lavato i denti")          #
        print("fatto tutto !")              #       all' if fatto_colazione
        print("posso uscire di casa!")      #
    else: 
        print("non ho lavato i denti")
        print("NON posso uscire di casa")
        
else:
    print("non ho fatto colazione")
    print("NON posso uscire di casa")<jupyter_output>ho fatto colazione
ho lavato i denti
fatto tutto !
posso uscire di casa!<jupyter_text>orPer verificare se almeno di due condizioni si è verificata, si usa `or`. Per esempio, possiamo stabilire che per fare colazione ci serve avere del latte intero o scremato (nota: se li abbiamo tutte e due riusciamo a fare colazione lo stesso !)<jupyter_code>ho_latte_intero = True
ho_latte_scremato = False

if ho_latte_intero or ho_latte_scremato:
    print("posso fare colazione !")
else: 
    print("NON posso fare colazione :-(")<jupyter_output>posso fare colazione !<jupyter_text>**✪ ESERCIZIO**: prova a scriverecqui sotto a mano il programma riportato nella cella presedente, ed eseguilo con Control+Invio. Prova a cambiare i valori da `True` a `False` e guarda che succede:Assicurati di provare tutti i casi:- True True- True False- False True- False False<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**✪✪ ESERCIZIO**: prova a fare un programma che ti dice se puoi uscire di casa solo se  hai fatto colazione (per cui devi avere hai almeno un tipo di latte) e lavato i denti<jupyter_code>ho_latte_intero = False
ho_latte_scremato = True
lavato_denti = False


# scrivi qui


if ho_latte_intero or ho_latte_scremato:
    print("posso fare colazione !")
    fatto_colazione = True
else: 
    print("NON posso fare colazione :-(")
    fatto_colazione = False

if fatto_colazione and lavato_denti:
    print("posso uscire di casa")
else:
    print("NON posso uscire di casa")<jupyter_output>posso fare colazione !
NON posso uscire di casa<jupyter_text>notPer le negazioni, puoi usare il `not`:<jupyter_code>not True
not False
fatto_colazione = False

if not fatto_colazione:
    print("Ho fame !")
else:
    print("che buoni che erano i cereali")
fatto_colazione = True

if not fatto_colazione:
    print("Ho fame !")
else:
    print("che buoni che erano i cereali")<jupyter_output>che buoni che erano i cereali<jupyter_text>✪✪ ESERCIZIO: prova a fare un programma che ti dice se puoi nuotare se NON hai fatto colazione E hai il salvagenteAssicurati di provare tutti i casi:- True True- True False- False True- False False<jupyter_code>hai_salvagente = True
fatto_colazione = True

# scrivi qui

if hai_salvagente and not fatto_colazione:
    print("puoi nuotare")
else:
    print("NON puoi nuotare")<jupyter_output>NON puoi nuotare<jupyter_text>Non solo True e False **ATTENZIONE ai booleani diversi da True e False !**In Python, il numero `0` e altri oggetti 'nulli' (come l'oggetto `None`, la stringa vuota `""` e la lista vuota `[]`) sono considerati `False`, e tutto ciò che non è 'nullo' è considerato `True`!  Facciamo degli esempi per mostrare quanto sopra riportato:<jupyter_code>if True:
    print("questo")    
    print("sarà")
    print("stampato")
else:
    print("quest'altro")
    print("non sarà stampato")<jupyter_output>questo
sarà
stampato<jupyter_text>Tutto ciò che non è 'nullo' è considerato `True`, verifichiamolo per esempio con la stringa `"ciao"`:<jupyter_code>if "ciao":
    print("anche questo")
    print("sarà stampato!!")
else:
    print("e questo no")
if False:
    print("io non sarò stampato")
else:
    print("io sì")
if 0:
    print("anche questo non sarà stampato")
else:
    print("io sì")
if None:
    print("neppure questo sarà stampato")
else:
    print("io sì")
if "":  # stringa vuota
    print("Neanche questo sarà stampato !!!")
else:
    print("io sì")<jupyter_output>io sì<jupyter_text>**✪ ESERCIZIO**: Copia qua sotto l'`if` una stringa con uno spazio dentro `" "`nella condizione dell'`if`. Cosa succederà?- prova anche a mettere una lista vuota `[]`, che succede?<jupyter_code># scrivi qui l'if 


if " ": # spazio
    print("Niente stampa!")
else:
    print("io sì")


if []: # lista vuota
    print("Niente stampa!")
else:
    print("io sì")<jupyter_output>Niente stampa!
io sì<jupyter_text>Stringhe - stringLe stringhe sono sequenze _immutabili_ di caratteri. **Riferimenti**: SoftPython:- [stringhe 1 - introduzione](https://it.softpython.org/strings/strings1-sol.html)- [stringhe 2 - operatori](https://it.softpython.org/strings/strings2-sol.html)- [stringhe 3 - metodi](https://it.softpython.org/strings/strings3-sol.html) - [stringhe 4 - altri esercizi](https://it.softpython.org/strings/strings4-sol.html) **Concatenare stringhe**Una delle cose che si fanno più frequentemente è concatenre delle stringhe:<jupyter_code>"ciao " + "mondo"<jupyter_output><empty_output><jupyter_text>Ma nota che quando concateniamo una stringa e un numero, Python si arrabbia: ```python"ciao " + 5``` ```bash---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last) in ()----> 1 "ciao " + 5TypeError: Can't convert 'int' object to str implicitly``` Questo succede perchè Python vuole che convertiamo esplicitamente il numero '5' in una stringa. Porrà simili lamentela anche con altri tipi di oggetti. Quindi, quando concatenate oggetti che non sono stringhe, per evitare problemi racchiudete l'oggetto da convertire nella funzione `str` come qui:<jupyter_code>"ciao " + str(7)<jupyter_output><empty_output><jupyter_text>Un modo alternativo e più veloce è usare l'operatore di formattazione percentuale `%`, che sostituisce alle occorrenze di `%s` quello che mettete dopo un `%` dopo la stringa :<jupyter_code>"ciao %s" % 7<jupyter_output><empty_output><jupyter_text>Meglio ancora, il `%s` può stare all'interno della stringa e venire ripetuto. Per ogni occorrenza si può passare un sostituto diverso, come per esempio nella tupla `("bello", "Python")` (una tupla è semplicemente una sequenza immutabile di elementi racchiusi tra parentesi tonde e separati da virgole)<jupyter_code>"Che %s finalmente imparo %s" % ("bello", "Python")<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: il `%s` funziona con le stringhe ma anche con quasiasi altro tipo di dato, per esempio un intero. Scrivi qua sotto il comando sopra, aggiunendo un `%s` alla fine della stringa, e aggiungendo alla fine della tupla il numero `3` (separandolo dagli altri con una virgola).Domanda: i `%s` possono stare uno dopo l'altro senza spazi tra di loro? Prova.<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>Usare metodi degli oggettiQuasi tutto in Python è un oggetto, faremo qui una velocissima introduzione tanto per dare l'idea.**Riferimenti**- [Pensare in Python, Capitolo 15, Classi e oggetti](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2016.html)- [Pensare in Python, Capitolo 16, Classi e funzioni](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2017.html)- [Pensare in Python, Capitolo 17, Classi e metodi](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2017.html)Quasi tutto in Python è un oggetto. Per esempio, le stringhe sono oggetti. Ogni tipo di oggetto ha delle azioni chiamati _metodi_ che si possono eseguire su quello oggetto. Per esempio, per le stringhe che rappresentano nomi potremmo voler rendere in maiuscolo la prima lettera: a tal fine possiamo cercare se per le stringhe ci sono giò metodi esistenti che fanno questo. Proviamo il metodo esistente  `capitalize()` sulla _stringa_ `"trento"` (notare che la stringa è tutta in minuscolo e _capital_ in inglese vuol anche dire 'maiuscolo' ):<jupyter_code>"trento".capitalize()<jupyter_output><empty_output><jupyter_text>Python ci ha appena fatto la cortesia di rendere la prima lettera della parola in maiuscolo `'Trento'`  **✪ ESERCIZIO**: Scrivi nella cella qua sotto `"trento".` e premi TAB: Jupyter dovrebbe suggerirti dei metodi disponibili per la stringa. Prova il metodo `upper()` e `count("t")`<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>Liste - listUna lista in python è una sequenza di elementi eterogenei, in cui possiamo mettere gli oggetti che vogliamo.**Riferimenti - SoftPython:**  - [Liste 1 - introduzione](https://it.softpython.org/lists/lists1-sol.html)- [Liste 2 - operatori](https://it.softpython.org/lists/lists2-sol.html)- [Liste 3 - metodi](https://it.softpython.org/lists/lists3-sol.html)- [Liste 4 - iterazione e funzioni](https://it.softpython.org/lists/lists4-sol.html)Creiamo una lista di stringhe:<jupyter_code>x = ["ciao", "soft", "python"]
x<jupyter_output><empty_output><jupyter_text>Le liste sono sequenze di oggetti possibilmente eterogenei, quindi dentro ci potete buttare di tutto, interi, stringhe, dizionari ...:<jupyter_code>x = ["ciao", 123, {"a":"b"}]
x<jupyter_output><empty_output><jupyter_text>Per accedere ad un elemento in particolare dentro una lista, si può usare un indice tra parentesi quadre che indica un elemento:<jupyter_code># primo elemento

x[0]  
# secondo elemento

x[1]
# terzo elemento

x[2]<jupyter_output><empty_output><jupyter_text>In una lista possiamo cambiare gli elementi con l'assegnazione:<jupyter_code># Cambiamo il _secondo_ elemento:

x[1] = "soft"
x
x[2] = "python"
x<jupyter_output><empty_output><jupyter_text>Per ottenere la lunghezza di una lista, possiamo usare `len`:<jupyter_code>x = ["ciao", "soft", "python"]

len(x)<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: prova ad accedere ad un elemento fuori dalla lista, e vedi che succede. - `x[3]` è dentro o fuori dalla lista? - C'è una qualche lista `x` per cui possiamo scrivere `x[len(x)]` senza problemi ?- se usi indici negativi, che succede? Prova -1, -2, -3, -4 ...<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>Possiamo aggiungere elementi alla fine di una lista usando il comando `append`:<jupyter_code>x = []
x
x.append("ciao")
x
x.append("soft")
x
x.append("python")
x<jupyter_output><empty_output><jupyter_text>Ordinamento listeLe liste possono ordinare comodamente con il metodo `.sort`, che funziona su tutti gli oggetti ordinabili. Per esempio, possiamo ordinare i numeri:**IMPORTANTE**:  `.sort()` modifica la lista su cui è chiamato, _non_ ne genera una nuova !<jupyter_code>x = [ 8, 2, 4]

x.sort()
x<jupyter_output><empty_output><jupyter_text>Come altro esempio, possiamo ordinare le stringhe:<jupyter_code>x = [ 'mondo', 'python',  'ciao',]

x.sort()
x<jupyter_output><empty_output><jupyter_text>Se non volessimo modificare la lista originale e invece volessimo generarne una nuova, useremmo la funzione `sorted()`. **NOTA**: `sorted` è una _funzione_, non un _metodo_:<jupyter_code>x = [ 'mondo', 'python', 'ciao',]

sorted(x)
# l'x originale non è cambiato:
x<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Che succede se ordini stringhe contenenti gli stessi caratteri ma maiscoli invece di minuscoli? Come vengono ordinati? Fai delle prove.<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**:  Che succede se nella stessa lista metti sia stringhe che numeri e provi ad ordinarla? Fai delle prove.<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**Ordine rovesciato**Supponiamo di voler ordinare la lista alla rovescia usando `sorted`. Per fare cioò possiamo indicare a Python il parametro booleano `reverse` e il suo valore, che in questo caso sarà `True`. Questo ci permette di notare come Python consenta di usare parametri opzionali specificandoli _per nome_ :<jupyter_code>sorted(['mondo', 'python', 'ciao'], reverse=True)<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Per cercare informazioni su `sorted`, avremmo potuto chiedere a Python dell'aiuto. Per fare ciò Python mette a disposizione una comoda funzione chiamata `help`, che potresti usare così `help(sorted)`. Prova ad eseguirla nella cella qua sotto. A volte l'help è piuttosto complesso, e sta a noi sforzarci un po' per individuare i parametri di interesse<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**Rovesciare liste non ordinate**E se volessimo rovesciare una lista così com'è, senza ordinarla in senso decrescente, per esempio per passare da`[6,2,4]` a `[2,4,6]` Cercando un po' nella libreria di Python, vediamo che c'è una comoda funzione `reversed()` che prende come paramatro la lista che vogliamo rovesciare e ne genera una nuova rovesciata. **✪ ESERCIZIO**: Prova ad eseguire `reversed([6,2,4])` nella cella qua sotto, e guarda che output ottieni. E' quello che ti aspetti ? In genere, e specialmente in Python 3, quando ci aspettiamo una lista e per caso vediamo invece un oggetto col nome `iterator`, possiamo risolvere passando il risultato come parametro della funzione `list()`<jupyter_code># scrivi qui il codice<jupyter_output><empty_output><jupyter_text>Dizionari - dictI dizionari sono dei contenitori che ci consentono di abbinare dei _valori_ a delle voci dette _chiavi_. Qua faremo un esempio rapidissimo per dare un'idea.**Riferimenti**:- [Pensare in Python, Capitolo 11, Dizionari](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2012.html)- SoftPython - dizionari:    1. [introduzione](https://it.softpython.org/dictionaries/dictionaries1-sol.html)    2. [operatori](https://it.softpython.org/dictionaries/dictionaries2-sol.html)    3. [metodi](https://it.softpython.org/dictionaries/dictionaries3-sol.html)    4. [iterazione e funzioni](https://it.softpython.org/dictionaries/dictionaries4-sol.html)    5. [strutture composte](https://it.softpython.org/dictionaries/dictionaries5-sol.html)Possiamo creare un dizionario con le graffe `{` `}`, separando le chiavi dai valori con i due punti `:`, e separando le coppie chiave/valore con la virgola `,`:<jupyter_code>d = {  'chiave 1':'valore 1', 'chiave 2':'valore 2'}<jupyter_output><empty_output><jupyter_text>Per accedere ai valori, possiamo usare le chiavi tra parentesi quadre:<jupyter_code>d['chiave 1']
d['chiave 2']<jupyter_output><empty_output><jupyter_text>**Valori**: come valori nei dizionari possiamo mettere quello che ci pare, numeri, stringhe, tuple, liste, altri dizionari ..<jupyter_code>d['chiave 3'] = 123
d
d['chiave 4'] = ('io','sono', 'una', 'tupla')
d<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: prova ad inserire nel dizionario delle coppie chiave valore con chiavi stringa e come valori delle liste e altri dizionari,<jupyter_code># scrivi qui:<jupyter_output><empty_output><jupyter_text>**Chiavi**: Per le chiavi abbiamo qualche restrizione in più. Dentro i dizionari possiamo anche inserire dei numeri interi come chiavi:<jupyter_code>d[123] = 'valore 3'
d<jupyter_output><empty_output><jupyter_text>o persino delle sequenze, purchè siano _immutabili_ come le tuple:<jupyter_code>d[('io','sono','una','tupla')] = 'valore 4'
d<jupyter_output><empty_output><jupyter_text>**ATTENZIONE**: Non tutti i tipi vanno bene a Python come chiavi. Senza andare nei dettagli, in genere non puoi inserire nei dizionari dei tipi che possono essere modificati dopo che sono stati creati.  **✪ ESERCIZIO**: - Prova ad inserire in un dizionario una lista tipo `['a','b']`come chiave, e come valore metti quello che vuoi. Python non dovrebbe permetterti di farlo, e ti dovrebbe mostrare la scritta `TypeError: unhashable type: 'list'`- prova anche ad inserire un dizionario come chiave (per es. anche il dizionario vuoto `{}`). Che risultato ottieni?  Visualizzare l'esecuzione con Python TutorAbbiamo visto i principali tipi di dati. Prima di procedere oltre, è bene vedere gli strumenti giusti per comprendere al meglio cosa succede quando si esegue il codice.[Python tutor](http://pythontutor.com/) è un ottimo sito online per visualizzare online l’esecuzione di codice Python, permettendo di andare avanti e _indietro_ nell'esecuzione del codice. Sfruttatelo più che potete, dovrebbe funzionare con parecchi degli esempi che tratteremo a lezione. Vediamo un esempio. **Python tutor 1/4**Vai sul sito [pythontutor.com](http://pythontutor.com/) e seleziona _Python 3_ ![pytut-1-8231](img/pytut-1.jpg) **Python tutor 2/4**![pytut-2-498273](img/pytut-2.jpg) **Python tutor 3/4**![pytut-3-89142](img/pytut-3.jpg) **Python tutor 4/4**![pytut-4-27854](img/pytut-4.jpg)  Debuggare codice in JupyterPython tutor è fantastico, ma quando esegui del codice in Jupyter e non funziona, come si può fare? Per ispezionare l'esecuzione, gli editor di solito mettono a disposizione uno strumento chiamato _debugger_, che permette di eseguire le istruzioni una per una. Al momento (Agosto 2018), il debugger di Jupyter che si chiama [pdb](https://davidhamann.de/2017/04/22/debugging-jupyter-notebooks/) è estramamente limitato . Per superarne le limitazioni, in questo corso ci siamo inventati una soluzione di ripiego, che sfrutta Python Tutor.Se inserisci del codice Python in una cella, e poi **alla fine della cella** scrivete l'istruzione `jupman.pytut()`, come per magia il codice precedente verrà visualizzato all'interno del foglio Jupyter con il debugger di Python Tutor.  **ATTENZIONE**: `jupman` è una collezione di funzioni di supporto che ci siamo inventati apposta per questo corso. Quando vedi comandi che iniziano con `jupman`, affinchè funzionino devi prima eseguire la cella in cima al documento. Riportiamo tale cella qua per comodità. Se non lo hai già fatto, eseguila adesso.<jupyter_code># Ricordati di eseguire questa cella con Control+Invio
# Questi comandi dicono a Python dove trovare il file jupman.py
import sys;
sys.path.append('../'); 
import jupman;<jupyter_output><empty_output><jupyter_text>Adesso siamo pronti a provare Python tutor con la funzione magica `jupman.pytut()`: **ATTENZIONE**: Per usare Python tutor dentro Jupyter dovete essere online. Una volta eseguita la cella successivo, dopo qualche secondo dovrebbe apparire il debugger di Python tutor:<jupyter_code>x = 5
y = 7
z = x + y

jupman.pytut()<jupyter_output><empty_output><jupyter_text>Python Tutor : Limitazione 1Python tutor è comodo, ma ci sono importanti limitazioni: **ATTENZIONE**: Python Tutor guarda dentro una cella sola!Quando usi Python tutor dentro Jupyter, l'unico codice che viene considerato da Python tutor è quello dentro la cella dove sta il comando jupman.pytut(). Quindi per esempio in queste due celle che seguono, solo `print(w)` apparirà dentro Python tutor   senza il `w = 3`. Se proverai a cliccare _Forward_ in Python tutor,  ti verrà segnalato che non è stata definita `w`<jupyter_code>w = 3
print(w)

jupman.pytut()<jupyter_output>3<jupyter_text>Per avere tutto in Python tutor devi mettere tutto il codice nella stessa cella:<jupyter_code>w = 3
print(w)

jupman.pytut()<jupyter_output>3<jupyter_text>Python Tutor : Limitazione 2Un'altra limitazione è la seguente:**ATTENZIONE**: Python tutor usa solo funzioni dalla distribuzione standard di Python**Python Tutor va bene per ispezionare semplici algoritmi che usano funzioni di base di Python. Se usate qualche libreria tipo `numpy`, potete provare **solo online** a selezionare `Python 3.6 with anaconda`![pytut-5-781302](img/pytut-5.jpg)  IterazioneSpesso è utile compiere azioni su ogni elemento di una sequenza.**Riferimenti**- SoftPython:    - [controllo di flusso - cicli for](https://it.softpython.org/control-flow/flow2-for-sol.html)    - [controllo di flusso - cicli while](https://it.softpython.org/control-flow/flow3-for-sol.html)    - [Pensare in Python, Capitolo 7, Iterazione](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2008.html)- [<NAME>, Lezione 8, L'istruzione while](http://ncassetta.altervista.org/Tutorial_Python/Lezione_08.html)**Cicli for**Tra i vari modi per farlo, uno è usare i cicli `for`<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for animale in animali:
    print("Nella lista ci sono:")
    print(animale)<jupyter_output>Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli
Nella lista ci sono:
alci<jupyter_text>Qua abbiamo definito la variabile `animale` (avremmo potuto chiamarla con qualunque nome, anche `pippo`). Per ogni elemento nella lista `animali`, vengono eseguite le istruzioni dentro il blocco. Ogni volta che le istruzioni vengono eseguite, la variabile `animale` assume uno dei valori della lista `animali`**ATTENZIONE**: RICORDATI I DUE PUNTI `:` ALLA FINE DELLA LINEA DEL FOR !!!**ATTENZIONE**: Per indentare il codice, usa SEMPRE sequenze di 4 spazi bianchi. Sequenze di 2 soli spazi per quanto consentite non sono raccomandate. **ATTENZIONE**: A seconda dell'editor che usi, premendo TAB potresti ottenere una sequenza di spazi bianchi come accade in Jupyter (4 spazi che sono raccomandati), oppure un carattere speciale di tabulazione (da evitare)! Per quanto noiosa questa distinzione ti possa apparire, ricordatela perchè potrebbe generare errori molto difficili da scoprire.<jupyter_code># Guardiamo cosa succede con Python tutor: 

animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for animale in animali:
    print("Nella lista ci sono:")
    print(animale)
    
jupman.pytut()<jupyter_output>Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli
Nella lista ci sono:
alci<jupyter_text>**✪ ESERCIZIO**: Proviamo a capire meglio tutti gli _Attenzione_ qua sopra. Scrivi qui sotto il `for` con gli animali di prima (niente copia e incolla!), vedi se funziona. Ricordati di usare 4 spazi per le indentazioni. - Poi prova a togliere i due punti alla fine e vedi che errore ti da Python- Riaggiungi i due punti, e adesso prova a variare l'indentazione. Prova a mettere due spazi all'inizio di entrambi i print, vedi se esegue- Adesso prova a mettere due spazi prima del primo print e 4 spazi prima del secondo, e vedi se esegue<jupyter_code># scrivi qui - copia il for di sopra<jupyter_output><empty_output><jupyter_text>for in rangeUn'altra iterazione molto comune è incrementare un contatore ad ogni ciclo. Python rispetto ad altri linguaggi offre un sistema piuttosto particolare che usa la funzione `range(n)`, che ritorna una sequenza con i primi numeri da 0 incluso a `n` _escluso_. La possiamo usare così:<jupyter_code>for indice in range(3):
    print(indice)
    
for indice in range(6):
    print(indice)<jupyter_output>0
1
2
3
4
5<jupyter_text>Guardiamo meglio con Python tutor:<jupyter_code>for indice in range(6):
    print(indice)

jupman.pytut()<jupyter_output>0
1
2
3
4
5<jupyter_text>Quindi possiamo usare questo stile come un'alternativa per listare i nostri animali:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for indice in range(3):
    print("Nella lista ci sono:")
    print(animali[indice])<jupyter_output>Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli<jupyter_text>Guardiamo meglio con Python tutor:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

for indice in range(3):
    print("Nella lista ci sono:")
    print(animali[indice])
    
jupman.pytut()<jupyter_output>Nella lista ci sono:
cani
Nella lista ci sono:
gatti
Nella lista ci sono:
scoiattoli<jupyter_text>FunzioniUna funzione prende dei parametri e li usa per produrre o riportare qualche risultato.**Riferimenti**- [Pensare in Python, Capitolo 3, Funzioni](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2004.html)- [Pensare in Python, Capitolo 6, Funzioni produttive](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2007.html) puoi fare tutto saltando la parte 6.5 sulla ricorsione.    **NOTA**: nel libro viene usato il termine strano 'funzioni produttive' per quelle funzioni che ritornano un valore, ed il termine ancora più strano 'funzioni vuote' per funzioni che non ritornano nulla ma fanno qualche effetto tipo stampa a video: ignora e dimentica questi termini !  - [<NAME>, Lezione 4, Funzioni](http://ncassetta.altervista.org/Tutorial_Python/Lezione_04.html)- [SoftPython, Esercizi sulle funzioni](https://it.softpython.org/functions/functions-sol.html)Per definire una funzione, possiamo usare la parola chiave `def`:<jupyter_code>def mia_stampa(x,y):   # RICORDATI I DUE PUNTI ':' ALLA FINE DELLA RIGA !!!!!
    print('Ora stamperemo la somma di due numeri')
    print('La somma è %s' % (x + y))<jupyter_output><empty_output><jupyter_text>Possiamo chiamare la funzione così:<jupyter_code>mia_stampa(3,5)<jupyter_output>Ora stamperemo la somma di due numeri
La somma è 8<jupyter_text>Vediamo meglio che succede con Python Tutor:<jupyter_code>def mia_stampa(x,y):    # RICORDATI I DUE PUNTI ':' ALLA FINE DELLA RIGA !!!!!
    print('Ora stamperemo la somma di due numeri')
    print('La somma è %s' % (x + y))

mia_stampa(3,5)

jupman.pytut()<jupyter_output>Ora stamperemo la somma di due numeri
La somma è 8<jupyter_text>La funzione appena dichiarata stampa dei valori, ma non ritorna nulla. Per fare una funzione che ritorni un valore, dobbiamo usare la parola chiava `return`Trovi questo tipo di funzioni  anche sul libro [Pensare in Python, Capitolo 6, Funzioni produttive](https://davidleoni.github.io/ThinkPythonItalian/html/thinkpython2007.html), di cui puoi fare tutto saltando la parte 6.5 sulla ricorsione. NOTA: nel libro viene usato il termine strano “funzioni produttive” per quelle funzioni che ritornano un valore, ed il termine ancora più strano “funzioni vuote” per funzioni che non ritornano nulla ma fanno qualche effetto tipo stampa a video: ignora questi strani termini !<jupyter_code>def mia_somma(x,y):
    s = x + y
    return s

mia_somma(3,5)

# Vediamo meglio  che succede con Python Tutor: 

def mia_somma(x,y):
    s = x + y
    return s

print(mia_somma(3,5))

jupman.pytut()<jupyter_output>8<jupyter_text>**✪ ESERCIZIO**: Se proviamo ad assegnare ad una variabile `x` il valore di ritorno delle funzione `mia_stampa` che apparantemente non ritorna nulla, che valore ci sarà in `x`? Prova a capirlo qua sotto:<jupyter_code># scrivi qui<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Scrivi qua sotto una funzione `media` che calcola e ritorna la media tra due numeri x e y in input<jupyter_code># scrivi qui



def media(x, y):
    return (x + y) / 2<jupyter_output><empty_output><jupyter_text>**✪✪ ESERCIZIO**: Scrivi qua sotto una funzione che chiameremo `iniziab` che prende una stringa `x` in ingresso. Se la stringa inizia con la lettera 'b', per esempio `'bianco'` la funzione stampa la scritta `bianco inizia con b`, altrimenti stampa `bianco non inizia con la b`. * Per controllare se il primo carattere è uguale alla `'b'`, usa l'operatore `==` (ATTENZIONE: è un DOPPIO uguale !)* Se la stringa è vuota la tua funzione può avere problemi? Come potresti risolverli? (Per separare più condizioni nell'`if`, usa l'operatore `and` oppure `or` a seconda di come hai costruito l'if).<jupyter_code># scrivi qui

def iniziab(x):
    if len(x) != 0 and x[0] == 'b':
        print(x + ' inizia con b')
    else:
        print(x + ' non inizia con b')
    
iniziab('bianco')        
iniziab('verde')
iniziab('')<jupyter_output>bianco inizia con b
verde non inizia con b
 non inizia con b<jupyter_text>Funzioni lambdaIn Python una variabile può contenere una funzione. Per esempio, sappiamo che `len("ciao")` ci dà la lunghezza della stringa `"ciao"`<jupyter_code>len("ciao")<jupyter_output><empty_output><jupyter_text>Proviamo a creare una variabile `mia_variabile` che punta alla funzione `len`. **NOTA**: _non_ abbiamo aggiunto parametri a `len`!<jupyter_code>mia_variabile = len<jupyter_output><empty_output><jupyter_text>Adesso possiamo usare `mia_variabile` esattamente come usiamo la funzione `len`, che da la lunghezza di sequenze come le stringhe<jupyter_code>mia_variabile("ciao")<jupyter_output><empty_output><jupyter_text>Possiamo anche riassegnare `mia_variabile` ad altre funzioni, per esempio `sorted`. Vediamo che succede:<jupyter_code>mia_variabile = sorted<jupyter_output><empty_output><jupyter_text>chiamando `mia_variabile`, ci aspettiamo di vedere i caratteri di `"ciao"` in ordine alfabetico:<jupyter_code>mia_variabile("ciao")<jupyter_output><empty_output><jupyter_text>In Python possiamo definire funzioni in una sola riga, con le cosiddette _funzioni lambda_:<jupyter_code>mia_f = lambda x: x + 1<jupyter_output><empty_output><jupyter_text>Cosa fa `mia_f` ? Prende un parametro `x` e ritorna il risultato di calcolare l'espressione `x + 1`:<jupyter_code>mia_f(5)<jupyter_output><empty_output><jupyter_text>Possiamo anche passare due parametri:<jupyter_code>mia_somma = lambda x,y: x + y
mia_somma(3,5)<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Prova a definire qua sotto una funzione lambda per calcolare la media tra due numeri `x` e `y`, e assegnala alla variabile `media`<jupyter_code># scrivi qui

media = lambda x,y: (x + y)/2

media(2,7)<jupyter_output><empty_output><jupyter_text>Trasformazioni sulle listeSupponiamo di voler prendere la lista di animali e generarne una nuova in cui tutti i nomi iniziano con la lettera maiuscola. Questa che vogliamo fare di fatto è la creazione di una nuova lista operando una trasformazione sulla precedente. Per fare ciò esistono diversi modi, quello più semplice è usare un ciclo `for` così Trasfomazioni con il for<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']


nuova_lista = []
for animale in animali:  # ad ogni ciclo la variabile 'animale' contiene un nome preso dalla lista 'animali'
    nuova_lista.append(animale.capitalize())   # aggiungiamo alla nuova lista il nome dell'animale corrente, con la prima lettera maiuscola 
nuova_lista 

#vediamo che succede con Python tutor
jupman.pytut()<jupyter_output><empty_output><jupyter_text>Nota importante: i metodi sulle stringhe non modificano mai la stringa originale, ma ne generano sempre una nuova. Quindi la lista originale `animali` conterrà ancora le stringhe originale senza modifiche:<jupyter_code>animali<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Prova a scrivere qua sotto un ciclo `for` (senza usare il copia e incolla!) che scorre la lista dei nomi degli animali e crea un'altra lista che chiameremo `m` in cui tutti i caratteri dei nomi degli animali sono in maiuscolo (usa il metodo `.upper()`)<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

# scrivi qui

animali = ['cani', 'gatti', 'scoiattoli', 'alci']
# Scrivi qua
m = []
for animale in animali:  # ad ogni ciclo la variabile 'animale' contiene un nome preso dalla lista 'animali'
    m.append(animale.upper())   # aggiungiamo alla nuova lista il nome dell'animale corrente, con la prima lettera maiuscola 
m<jupyter_output><empty_output><jupyter_text>Trasformazioni con le _list comprehension_**Riferimenti**: [SoftPython - Sequenze](https://it.softpython.org/sequences/sequences-sol.htmlList-comprehensions)La stessa identica trasformazione di sopra si potrebbe attuare con una cosiddetta _list comprehension_,  che servono per generare nuove liste eseguendo la stessa operazione su tutti gli elementi di una lista esistente di partenza. Come sintassi imitano le liste, infatti iniziano e finiscono con le parentesi quadre, ma dentro contengono un for speciale per ciclare dentro un sequenza :<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.capitalize() for animale in animali]
nuova_lista<jupyter_output><empty_output><jupyter_text>Vediamo che succede con Python tutor:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

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

jupman.pytut()<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: Prova qua sotto ad usare una list comprehension per mettere tutti i caratteri in maiuscolo<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']
# scrivi qui


animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = [animale.upper() for animale in animali]<jupyter_output><empty_output><jupyter_text>**Filtrare con le comprehension**: Volendo, possiamo anche filtrare i dati usando un `if` speciale da mettere alla fine della comprehension. Per esempio potremmo selezionare solo gli animali la cui lunghezza del nome è di 4 caratteri:<jupyter_code>[animale.upper() for animale in animali if len(animale) == 4]<jupyter_output><empty_output><jupyter_text>Trasformazioni con le mapUn'altro modo ancora per trasformare una lista in una nuova è usare l'operazione `map`, che a partire da una lista, ne genera un'altra applicando ad ogni elemento della lista di partenza una funzione `f` che passiamo come parametro. Per risolvere lo stesso esercizio precedente, si potrebbe per esempio creare al volo con `lambda` una funzione `f` che mette la prima lettera di una stringa in maiuscolo, e poi si potrebbe chiamare la `map` passando la `f` appena creata:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']


f = lambda animale: animale.capitalize()

map(f, animali)<jupyter_output><empty_output><jupyter_text>Purtroppo il risultato non è esattamente la lista che volevamo. Il problema è che Python 3 aspetta a ritornarci una lista vera e propria, e invece ci ritorna un _iteratore_. Come mai? Python 3 per ragioni di efficienza spera che non non andremo mai ad usare nessun elemento della nuova lista, evitandogli di fatto la fatica di applicare la funzione a tutti gli elementi della lista originale. Ma noi possiamo forzarlo a darci la lista che vogliamo usando la funzione `list`:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

f = lambda animale: animale.capitalize()

list(map(f, animali))<jupyter_output><empty_output><jupyter_text>Per avere un esempio totalmente equivalente ai precedenti, possimao assegnare il risultato a `nuova_lista`:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

f = lambda animale: animale.capitalize()

nuova_lista = list(map(f, animali))
nuova_lista<jupyter_output><empty_output><jupyter_text>Un vero hacker Python probabilmente preferirà scrivere tutto in una sola linea, così:<jupyter_code>animali = ['cani', 'gatti', 'scoiattoli', 'alci']

nuova_lista = list(map(lambda animale: animale.capitalize(), animali))
nuova_lista<jupyter_output><empty_output><jupyter_text>**✪ ESERCIZIO**: la lista originale `animali` è cambiata? Controlla. **✪ ESERCIZIO**: Data una lista di numeri `numeri = [3, 5, 2, 7]` prova a scrivere una `map` che genera una nuova lista con i numeri raddoppiati, come `[6, 10, 4, 14]`:<jupyter_code>numeri = [3, 5, 2, 7]

# scrivi qui

numeri = [3,5,2,7]

list(map(lambda x: x * 2, numeri))<jupyter_output><empty_output><jupyter_text>MatriciFinita la presentazione, è ora di sforzarsi un po' di più. Vediamo brevemente matrici come liste di liste. Per approfondire, guardare i riferimenti.**Riferimenti**:- [SoftPython - matrici come liste di liste](https://it.softpython.org/matrices-lists/matrices-lists-sol.html)- [SoftPython - matrici numpy](https://it.softpython.org/matrices-numpy/matrices-numpy-sol.html)**✪✪ ESERCIZIO**: Date le due liste con nomi di animali e corrispondente aspettativa di vita in anni:```pythonanimali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']anni = [12,14,30,6,25]```Scrivere nella cella sotto del codice che generi una lista di liste da due elementi, così:`[  ['cane', 12],   ['gatto', 14],   ['pellicano', 30],   ['scoiattolo', 6],   ['aquila', 25]]`<jupyter_code>animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui


coppie = []
for i in range(len(animali)):
    coppie.append([animali[i], anni[i]])
coppie<jupyter_output><empty_output><jupyter_text>**✪✪ ESERCIZIO** modificare scrivendolo qua sotto il codice dell'esercizio precedente nella versione con il normale ciclo `for` per filtrare solo le specie con aspettativa di vita superiore ai 13 anni, così da ottenere questo risultato:```python[['gatto', 14], ['pellicano', 30], ['aquila', 25]]```<jupyter_code>animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

coppie = []
for i in range(len(animali)):
    if anni[i] > 13:
        coppie.append([animali[i], anni[i]])
coppie<jupyter_output><empty_output><jupyter_text>**ESERCIZIO** Scrivi qua sotto del codice con un normale ciclo `for` filtri solo le specie con aspettativa di vita  superiore ai 10 anni e inferiore ai 27, così da ottenere questo risultato:```python[['cane', 12], ['gatto', 14], ['aquila', 25]]```**SUGGERIMENTO**: in Pyhton per imporre due condizioni in un if si usa la parola chiave **and**<jupyter_code>animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]


coppie = []
for i in range(len(animali)):
    if anni[i] > 10 and anni[i] < 27 :
        coppie.append([animali[i], anni[i]])
coppie<jupyter_output><empty_output><jupyter_text>Funzione zipLa funzione `zip` prende due liste e ne restituisce una terza nuova, in cui mette coppie di elementi come tuple (che ricordiamo sono come le liste ma immutabilii), abbinando il primo elemento della prima lista a primo elemento della seconda lista, il secondo elemento della prima lista al secondo elemento della secondo e così via :<jupyter_code>list(zip(['a','b','c'], [5,2,7]))<jupyter_output><empty_output><jupyter_text>Perchè abbiamo messo anche `list` nell'esempio? Perchè `zip` ha lo stesso problema della map, cioè non ritorna subito una lista come vorremmo noi:<jupyter_code>zip(['a','b','c'], [5,2,7])<jupyter_output><empty_output><jupyter_text>**✪✪✪ ESERCIZIO**: Come vedi con la `zip` abbiamo ottenuto un risultato simile a quello del precedente esercizio, ma abbiamo tuple con parentesi tonde invece di liste con parentesi quadre. Riusciresti aggiungendo una `list comprehension` o una `map` ad ottenere lo stesso identico risultato?- per convertire una tupla in una lista, usa la funzione `list`:<jupyter_code>list(  ('ciao', 'soft', 'python')  )  # all'interno abbiamo messo una tupla, delimitata da parentesi tonde
animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui - soluzione con list comprehension

[ list(c) for c in zip(animali, anni) ]

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui - soluzione con map

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]
list(map(list, zip(animali, anni)))<jupyter_output><empty_output><jupyter_text>**✪✪✪ ESERCIZIO**: svolgi l'esercizio precedente filtrando gli animali con aspettativa di vita superiore ai 13 anni, usando la `zip` e una list comprehension<jupyter_code>animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]


# scrivi qui

animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

[ list(c) for c in zip(animali, anni) if c[1] > 13 ]<jupyter_output><empty_output><jupyter_text>**✪✪ ESERCIZIO**: Date le due liste con nomi di animali e corrispondente aspettativa di vita in anni come sopra, scrivere nella cella sotto del codice che con un normale ciclo `for` generi un dizionario che associa alla specie l'aspettativa di vita, così:```python{ 'aquila': 25, 'cane': 12, 'gatto': 14,  'pellicano': 30,  'scoiattolo': 6}```**ATTENZIONE**: A seconda della versione esatta di Python che avete e di come il dizionario viene creato, l'ordine dei campi quando viene stampato potrebbe differire dall'esempio. Questo è perfettamente normale, perchè le chiavi di un dizionario sono da intendersi come un insieme senza ordine particolare. Se volete essere sicuri di trovare le chiavi stampate nell'ordine in cui sono state inserite, dovete usare un OrderedDict<jupyter_code>animali = ['cane', 'gatto', 'pellicano', 'scoiattolo', 'aquila']
anni = [12,14,30,6,25]

# scrivi qui

d = {}
for i in range(len(animali)):
    d[animali[i]] = anni[i]
d<jupyter_output><empty_output><jupyter_text>Per ottenere lo stesso risultato in una linea, è possibile usare la funzione `zip` come fatto negli esercizi precedenti, e poi la funzione `dict` che crea un dizionario a partire dalla lista di coppie di elementi generata dallo `zip`:<jupyter_code>dict(zip(animali, anni))<jupyter_output><empty_output><jupyter_text>**✪✪ ESERCIZIO**: Data una lista di prodotti contenente a sua volta liste ciascuna con tipologia, marca e quantità di confezioni vendute:```pythonvendite = [    ['pomodori', 'Santini', 5],    ['pomodori', 'Cirio', 1],    ['pomodori', 'Mutti', 2],    ['cereali', 'Kelloggs', 3],    ['cereali', 'Choco Pops', 8],    ['cioccolata','Novi', 9],    ['cioccolata','Milka', 4],]```Usando un normale ciclo for, scrivere del codice Python nella cella sotto per creare un dizionario in cui le chiavi sono le tipologie e i valori sono la somma delle confezioni vendute per quella categoria:```python{ 'cereali': 11,  'cioccolata': 13, 'pomodori': 8   }```**SUGGERIMENTO**: fare attenzione ai due casi, quando il dizionario da ritornare ancora non contiene la tipologia estratta dalla lista correntemente in esame e quando invece già la contiene:<jupyter_code>vendite = [
    ['pomodori', 'Santini', 5],
    ['pomodori', 'Cirio', 1],
    ['pomodori', 'Mutti', 2],
    ['cereali', 'Kelloggs', 3],
    ['cereali', 'Choco Pops', 8],
    ['cioccolata','Novi', 9],
    ['cioccolata','Milka', 4],
]

# scrivi qui

vendite = [
    ['pomodori', 'Santini', 5],
    ['pomodori', 'Cirio', 1],
    ['pomodori', 'Mutti', 2],
    ['cereali', 'Kelloggs', 3],
    ['cereali', '<NAME>', 8],
    ['cioccolata','Novi', 9],
    ['cioccolata','Milka', 4],
]


d = {}
for vendita in vendite:
    if vendita[0] in d:
        d[vendita[0]] += vendita[2]
    else:
        d[vendita[0]] = vendita[2]
d<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10403899994126514, 'fraction_numerical': 0.010435225248154746, 'mean_word_length': 5.424905660377359, 'pattern_counts': {'":': 4, '<': 371, '<?xml version=': 0, '>': 375, 'https://': 36, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '97', 'dir': 'jupyter-structured-clean-dedup', 'id': '503358', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 18976, 'n_tokens_neox': 18755, 'n_words': 5918, 'path': 'quick-intro/quick-intro-sol.ipynb', 'repo_name': 'DavidLeoni/softpython-', 'size': '51099'}