Analisi dati in python

Introduzione a python

Python è un linguaggio di programmazione "inventato" dall'olandese Guido Van Rossum nel 1989, per correggere i difetti degli altri linguaggi di programmazione.

Caratteristiche di python:

  • Linguaggio interpretato, quindi INTERATTIVO! (i comandi vengono eseguiti immediatamente, non c'è bisogno di compilazione!);
    Tuttavia è possibile (anzi suggerito!) di creare brevi programmi (scripts) per riunire i comandi ed eseguirli in funzione di differenti parametri!
    Esempio:
In [1]:
10*13
Out[1]:
130
In [5]:
a=1.25
b=3.14
a*b
Out[5]:
3.9250000000000003
  • Linguaggio orientato agli oggetti (object-oriented)
  • Disponibilità di una pletora di librerie (funzioni già pronte all'uso!) per fare una quantità di operazioni che in altri linguaggi richiederebbero decine o centinaia di istruzioni! Ci sono librerie di calcolo, grafiche, per interagire col sistema operativo e con i dispositivi, per leggere ed elaborare decine di formati, ecc.
  • Esempio: (attenzione! Funziona solo dalla rete interna di fisica!)
In [ ]:
import smtplib

host = smtplib.SMTP( "mb.fis.unical.it" )
ret  = host.sendmail( "lprimavera@fis.unical.it", "leonardo.primavera@unical.it", "Ciao Leo!" )
host.quit()
  • Sintassi estremamente chiara: i programmi scritti in python sono estremamente semplici da leggere. Inoltre esistono una serie di comandi (help(), type(), dir()) che forniscono aiuto diretto nel ricordare i comandi e le funzioni.
    Esempio:
In [1]:
import math
type(math.pi)
Out[1]:
float
  • Scritto in C ed estensibile in C e C++
  • Portabile su qualsiasi piattaforma (Windows, Linux, Mac OS X, Unix BSD, Playstation, Digital VMS, Pocket PC, Windows CE, Amiga 500, ecc.). Per scaricarlo, visitare il sito: http://www.python.org

Nota importante: differenze tra python 2.7.x e 3.x

Python è un linguaggio in evoluzione. Nel passaggio dalla versione 2.7 alla versione 3 sono stati effettuati vari cambiamenti che rendono molti scripts scritti per la versione 2.7 incompatibili con la versione 3. Le differenze fondamentali riguardano l'introduzione delle stringhe Unicode per consentire codifiche avanzate rispetto a quella ASCII semplice, le istruzioni di input/output e i files. In queste lezioni utilizzaremo la versione 3 di python, tuttavia cercheremo di sottolineare le differenze con la versione 2.7 dove possibile. Quale delle due versioni utilizzare dipende dalle varie necessità: non tutte le librerie di python sono state portate dalla versione 2.7.x alla versione 3.x. Tuttavia, probabilmente, la versione 2.7 scomparirà prima o poi, anche se sul sito di python si possono tuttora scaricare entrambe!

Tipi di dati

Nei linguaggi di programmazione si utilizzano variabili per contenere dati numerici di vario tipo, caratteri, sequenze di caratteri (stringhe), ecc.
Le variabili possono essere di vario tipo: interi, reali (singola e doppia precisione), caratteri, stringhe.
Nei linguaggi compilati, il tipo di dato contenuto nelle variabili deve essere dichiarato prima di utilizzare la variabile e non può essere cambiato in seguito! In python una variabile non deve essere dichiarata, basta inizializzarla, e può essere re-inizializzata dovunque, cambiandole così il tipo!
Esempio:

In [16]:
a=100
type(a)
Out[16]:
int
In [17]:
b=18.25
type(b)
Out[17]:
float
In [18]:
s="Ciao!"
type(s)
Out[18]:
str

Caratteristiche dei tipi di dati in python

Differenze fra i tipi di dati in python e in altri linguaggi:
  • Gli interi sono a precisione infinita!
    Esempio: (2 elevato a 10000!)
In [19]:
2**10000
Out[19]:
19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376L
  • I numeri reali sono sempre almeno in doppia precisione!
    Esempio:
  • In [1]:
    10.0**0.5
    
    Out[1]:
    3.1622776601683795
    
  • Esiste un tipo complesso per i numeri complessi!
    Esempio: la radice quadrata del numero complesso \(1+2\textrm{i}\)
  • In [21]:
    a=1.0+2.0j
    a**0.5
    
    Out[21]:
    (1.272019649514069+0.7861513777574233j)
    
  • Il tipo Booleano viene indicato con i valori "True" o "False" (nota che le maiuscole sono obbligatorie!)
    Esempio:
  • In [22]:
    x=10
    a=x>5
    a
    
    Out[22]:
    True
    

    Conversioni di tipo

    Le seguenti funzioni effettuano le conversioni da un tipo ad un altro:
    • str(numero): converte un numero in stringa;
    • int(stringa) oppure int(reale): converte da stringa o reale a numero intero;
    • float(stringa) oppure float(int): converte da stringa o intero a numero reale.

    Esempi:

    In [42]:
    a=12.2
    s=str(a)
    s
    
    Out[42]:
    '12.2'
    
    In [44]:
    s="3.1415926"
    float(s)
    
    Out[44]:
    3.1415926
    
    In [2]:
    s='12345'
    int(s)
    
    Out[2]:
    12345
    

    Liste

    In tutti i linguaggi di programmazione si definiscono i cosiddetti vettori, cioé variabili indicizzate in sequenza che contengono dati tutti dello stesso tipo (esempio: un insieme di numeri di cui calcolare la media, ecc.).
    In python la stessa funzione è svolta dalle liste che però, a differenza dei vettori negli altri linguaggi di programmazione, possono contenere elementi eterogenei (cioé non dello stesso tipo!).
    Esempi:

    In [23]:
    elenco=[1.2,3.45,7.36,8.55]
    elenco
    
    Out[23]:
    [1.2, 3.45, 7.36, 8.55]
    
    In [24]:
    elenco=[1,2,3,"stella"]
    elenco
    
    Out[24]:
    [1, 2, 3, 'stella']
    

    I singoli elementi di una lista sono indicizzati tramite la loro posizione all'interno della lista con un indice che varia tra 0 ed il numero di elementi nella lista - 1, racchiuso tra parentesi quadre:

    In [33]:
    elenco=[1,3,5,7,9]
    elenco[3]
    
    Out[33]:
    7
    

    Ogni elemento di una lista può essere modificato:

    In [34]:
    elenco[2]=101
    elenco
    
    Out[34]:
    [1, 3, 101, 7, 9]
    

    Lo slicing di una lista è una operazione che permette di estrarre una parte della lista (nota che vengono restituiti gli elementi dal primo indice al secondo - 1!):

    In [35]:
    elenco[0:3]
    
    Out[35]:
    [1, 3, 101]
    

    Un indice negativo indica l'elemento della lista a partire dall'ultimo:

    In [36]:
    elenco[0:-2]
    
    Out[36]:
    [1, 3, 101]
    

    Se il primo o l'ultimo elemento non sono indicati, si assumono lo 0 e l'ultimo elemento:
    Esempio (stampa gli ultimi 2 elementi):

    In [37]:
    elenco[-2:]
    
    Out[37]:
    [7, 9]
    
    In [38]:
    elenco[:2]
    
    Out[38]:
    [1, 3]
    

    Per eliminare una serie di elementi da una lista, basta porli uguali alla lista vuota:

    In [39]:
    elenco[2:4]=[]
    elenco
    
    Out[39]:
    [1, 3, 9]
    

    Lo slicing può contenere un terzo indice, che estrae gli elementi dal primo indice all'ultimo meno 1, a passi del terzo indice.
    Esempio:

    In [71]:
    elenco=[1,2,3,4,5,6,7,8,9,10]
    elenco[2:10:2]
    
    Out[71]:
    [3, 5, 7, 9]
    

    Metodi per le liste

    • append(elem):
      appende un elemento "elem" in coda alla lista
    • insert(int,elem):
      inserisce l'elemento "elem" nella posizione int (parte da 0!). Nota: per inserire alla fine della lista basta selezionare un indice maggiore o uguale dell'ultimo elemento della lista!
    • extend([list]):
      estende la lista con un'altra lista "list" formando un'unica lista più lunga
    • remove(elem):
      rimuove l'elemento "elem" dalla lista (contrario di insert!)
    • pop() o pop(int):
      estrae e stampa l'ultimo elemento della lista, se manca "int", oppure l'elemento numero "int"
    • count(elem):
      conta gli elementi uguali a "elem" nella lista
    • index(elem):
      dà la posizione della prima occorrenza di "elem" nella lista (attenzione! Se l'elemento non esiste da' un errore!)
    • reverse():
      inverte la lista (attenzione! la lista viene sovrascritta!)
    • sort():
      ordina la lista, con diversi criteri (attenzione, la lista viene sovrascritta!)

    Esempi:

    In [3]:
    elenco=[1,2,3,4,5]
    elenco
    
    Out[3]:
    [1, 2, 3, 4, 5]
    
    In [4]:
    elenco.append(10)
    elenco
    
    Out[4]:
    [1, 2, 3, 4, 5, 10]
    
    In [5]:
    elenco.insert(1,11)
    elenco
    
    Out[5]:
    [1, 11, 2, 3, 4, 5, 10]
    
    In [6]:
    elenco.extend([20,30,40,50])
    elenco
    
    Out[6]:
    [1, 11, 2, 3, 4, 5, 10, 20, 30, 40, 50]
    
    In [7]:
    elenco.remove(20)
    elenco
    
    Out[7]:
    [1, 11, 2, 3, 4, 5, 10, 30, 40, 50]
    
    In [8]:
    elenco.pop()
    
    Out[8]:
    50
    
    In [9]:
    elenco
    
    Out[9]:
    [1, 11, 2, 3, 4, 5, 10, 30, 40]
    
    In [10]:
    elenco.append(1)
    elenco.count(1)
    
    Out[10]:
    2
    
    In [11]:
    elenco
    
    Out[11]:
    [1, 11, 2, 3, 4, 5, 10, 30, 40, 1]
    
    In [12]:
    elenco.index(1)
    
    Out[12]:
    0
    
    In [13]:
    elenco.pop(0)
    
    Out[13]:
    1
    
    In [14]:
    elenco.index(1)
    
    Out[14]:
    8
    
    In [15]:
    elenco.reverse()
    elenco
    
    Out[15]:
    [1, 40, 30, 10, 5, 4, 3, 2, 11]
    
    In [19]:
    elenco.sort()
    elenco
    
    Out[19]:
    [1, 2, 3, 4, 5, 10, 11, 30, 40]
    
    In [20]:
    elenco.sort(reverse=True)
    elenco
    
    Out[20]:
    [40, 30, 11, 10, 5, 4, 3, 2, 1]
    

    Operatore "in"

    L'operatore "in" restituisce True o False a seconda che il termine a sinistra esista o no nella lista!
    Esempio:

    In [25]:
    ll=[1,3,5,7,9,11]
    3 in ll
    
    Out[25]:
    True
    
    In [26]:
    4 in ll
    
    Out[26]:
    False
    

    Funzione len

    La funzione len(list) restituisce la lunghezza (il numero di elementi) in una lista.
    Esempio:

    In [2]:
    ll=[10,20,30,40,50]
    print(len(ll))
    
    5
    
    

    Liste di liste (arrays)

    In quasi tutti i linguaggi esistono variabili con 2 indici, equivalenti alle matrici in matematica. In python si possono creare variabili con due (o più!) indici, come liste di liste.
    Esempio:

    In [13]:
    arr=[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
    arr
    
    Out[13]:
    [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
    
    In [14]:
    arr[1]
    
    Out[14]:
    [4, 5, 6]
    
    In [15]:
    arr[1][2]
    
    Out[15]:
    6
    

    Stringhe

    Le stringhe in python sono sequenze di caratteri delimitati da singoli o doppi apici.
    Due stringhe si possono concatenare con l'operatore "+":

    In [16]:
    s1="Ciao"
    s2="mondo!"
    s1 + ' ' + s2
    
    Out[16]:
    'Ciao mondo!'
    

    Le stringhe possono ripetersi utilizzando l'operatore "*":

    In [17]:
    s1="Python e' "
    s2="bello, "
    s1 + s2 * 10 + "bello!"
    
    Out[17]:
    "Python e' bello, bello, bello, bello, bello, bello, bello, bello, bello, bello, bello!"
    

    Le stringhe possono contenere caratteri speciali (sequenze di escape) come "ritorno a capo", "tabulatori", "codici ascii" (in esadecimale!), ecc.

    In [3]:
    s1="Ricordati di mandare una email a:\n"
    s2="\t"
    s3="lprimavera\x40fis.unical.it"
    print(s1 + s2 + s3)
    
    Ricordati di mandare una email a:
    	lprimavera@fis.unical.it
    
    

    Le stringhe possono estendersi su più righe inserendole tra tripli apici o virgolette:

    In [5]:
    s="""
    Questo e' un esempio di una stringa molto lunga...
    davvero molto lunga...
    """
    print(s)
    
    
    Questo e' un esempio di una stringa molto lunga...
    davvero molto lunga...
    
    
    

    Le stringhe si comportano come liste, per cui si può effettuare lo slicing:

    In [20]:
    s="abcdefghilmnopqrstuvz"
    s[1:-1]
    
    Out[20]:
    'bcdefghilmnopqrstuv'
    
    In [21]:
    s[::4]
    
    Out[21]:
    'aeiosz'
    

    Nota, peró, che a differenza delle liste, le stringhe sono immutabili, quindi non possono essere cambiate!
    Esempio:

    In [22]:
    s="aeiou"
    s[2]="c"
    
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-22-7992904794b8> in <module>()
          1 s="aeiou"
    ----> 2 s[2]="c"
    
    TypeError: 'str' object does not support item assignment
    Come per le liste, esistono metodi speciali anche per le stringhe:
    • find(str): cerca str all'interno della stringa.
    • strip(): elimina gli spazi iniziali e finali dalla stringa.
    • replace(str1,str2): rimpiazza str1 con str2 nella stringa.
    • split(str): splitta la stringa secondo la str. Nota che il risultato e' una lista!
    • str.join(lista): unisce gli elementi della lista argomento con la stringa str

    Esempi:

    In [23]:
    s='  abcde  '
    s.find("c")
    
    Out[23]:
    4
    
    In [24]:
    s.strip()
    
    Out[24]:
    'abcde'
    
    In [25]:
    s.replace(" ","<<")
    
    Out[25]:
    '<<<<abcde<<<<'
    
    In [26]:
    s="Questa stringa contiene alcune virgole, che servono a migliorarne la lettura, ma a volte e' bene separare le varie frasi"
    s.split(",")
    
    Out[26]:
    ['Questa stringa contiene alcune virgole',
     ' che servono a migliorarne la lettura',
     " ma a volte e' bene separare le varie frasi"]
    
    In [27]:
    '/'.join(["12","10","1492"])
    
    Out[27]:
    '12/10/1492'
    

    Ulteriori metodi per le stringhe possono ottenersi con i comandi: dir(s) o help(s):

    In [28]:
    dir(s)
    
    Out[28]:
    ['__add__',
     '__class__',
     '__contains__',
     '__delattr__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__getitem__',
     '__getnewargs__',
     '__getslice__',
     '__gt__',
     '__hash__',
     '__init__',
     '__le__',
     '__len__',
     '__lt__',
     '__mod__',
     '__mul__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__rmod__',
     '__rmul__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '_formatter_field_name_split',
     '_formatter_parser',
     'capitalize',
     'center',
     'count',
     'decode',
     'encode',
     'endswith',
     'expandtabs',
     'find',
     'format',
     'index',
     'isalnum',
     'isalpha',
     'isdigit',
     'islower',
     'isspace',
     'istitle',
     'isupper',
     'join',
     'ljust',
     'lower',
     'lstrip',
     'partition',
     'replace',
     'rfind',
     'rindex',
     'rjust',
     'rpartition',
     'rsplit',
     'rstrip',
     'split',
     'splitlines',
     'startswith',
     'strip',
     'swapcase',
     'title',
     'translate',
     'upper',
     'zfill']
    

    Tuple

    Le tuple sono simili alle liste, ma sono immutabili come le stringhe, quindi non possono essere modificate!
    Vengono utilizzate spesso per creare arrays di una data dimensione in numpy.
    Per definire una tupla, si debbono usare le parentesi tonde (le quadre sono riservate alle liste!).
    Esempio:

    In [29]:
    a=(1,2,3,4,'mha!')
    a[1:-1]
    
    Out[29]:
    (2, 3, 4)
    
    In [30]:
    a[1]
    
    Out[30]:
    2
    
    In [31]:
    a[1]=18
    
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-31-1b7326119766> in <module>()
    ----> 1 a[1]=18
    
    TypeError: 'tuple' object does not support item assignment

    Dizionari

    Un dizionario in python è un array associativo, cioé funziona come una lista, ma invece di fare riferimento al valore dei singoli elementi in base ad un numero progressivo, ci si riferisce ad essi tramite una chiave.
    Per creare un dizionario occorre inizializzarlo con il costrutto "dict()", quindi aggiungervi le coppie chiave-valore.
    Esempio:

    In [6]:
    dieta=dict()
    dieta["Pasta"]=125
    dieta["Carne"]=300
    dieta["Frutta"]=150
    dieta
    
    Out[6]:
    {'Pasta': 125, 'Frutta': 150, 'Carne': 300}
    

    Un dizionario può anche essere inizializzato con le parentesi graffe, seguite dalle chiavi e dai valori.
    Esempio:

    In [7]:
    dd={"Carne": 300, "Frutta": 150, "Pasta": 125}
    dd
    
    Out[7]:
    {'Pasta': 125, 'Frutta': 150, 'Carne': 300}
    

    Ogni valore può essere ricavato dalla rispettiva chiave.
    Esempio:

    In [8]:
    print(dd["Carne"])
    
    300
    
    

    Nuovi elementi possono essere aggiunti al dizionario semplicemente aggiungendo una nuova chiave ed un nuovo valore. Analogamente, ogni coppia chiave-valore può essere rimossa con l'istruzione "del".
    Esempio:

    In [9]:
    dieta["Insalata"]="A piacimento"
    dieta
    
    Out[9]:
    {'Pasta': 125, 'Frutta': 150, 'Insalata': 'A piacimento', 'Carne': 300}
    
    In [36]:
    del dieta["Carne"]
    dieta
    
    Out[36]:
    {'Frutta': 150, 'Insalata': 'A piacimento', 'Pasta': 125}
    

    Metodi per i dizionari

    Come per le liste, esistono diversi metodi anche per i dizionari. I seguenti sono i metodi principali, ne esistono molti altri:
    • clear():
      cancella tutti gli elementi di un dizionario;
    • keys():
      restituisce una lista con tutte le chiavi del dizionario;
    • values():
      restituisce una lista con l'insieme dei valori del dizionario;
    • items():
      restituisce una lista di tuple che contengono le coppie chiave-valore per ogni elemento del dizionario;
    • has_key(str):
      restituisce True o False a seconda che la stringa "str" esista tra le chiavi del dizionario.

    Esempi:

    In [37]:
    dieta.keys()
    
    Out[37]:
    ['Pasta', 'Frutta', 'Insalata']
    
    In [38]:
    dieta.values()
    
    Out[38]:
    [125, 150, 'A piacimento']
    
    In [39]:
    dieta.items()
    
    Out[39]:
    [('Pasta', 125), ('Frutta', 150), ('Insalata', 'A piacimento')]
    
    In [40]:
    dieta.has_key("Carne")
    
    Out[40]:
    False
    
    In [41]:
    dieta.has_key("Frutta")
    
    Out[41]:
    True
    
    In [42]:
    dieta.clear()
    dieta
    
    Out[42]:
    {}
    

    Sintassi del linguaggio

    Costrutto if

    Serve per eseguire un blocco di istruzioni quando una data condizione è verificata.
    if cond1:
       ...
    elif cond2:
       ...
    else:
       ...
    
    Nota che:
    • non c'è limite al numero di "elif" che possono apparire;
    • l'ultimo "else" NON è obbligatorio!

    Esempio:

    In [10]:
    if 1==2:
       print("Falso")
    elif 1==3:
       print("Falso")
    else:
       print("Vero!")
    
    Vero!
    
    

    Operatori condizionali

    Si hanno i seguenti operatori che possono essere utilizzati per valutare le condizioni:
    • ==: uguaglianza;
    • >, <b><, >=, <b><=: maggiore, minore, maggiore o uguale, minore o uguale;
    • != : disuguaglianza.

    Costrutto for

    Serve per eseguire cicli ed operazioni ripetitive.
    for var in sequenza:
       ...
    
    In [11]:
    for var in "aeiou":
        print(var)
    
    a
    e
    i
    o
    u
    
    

    Molto utile con il costrutto for è la funzione range(start,stop,jump), che restituisce una lista di interi che inizia da "start" fino a "stop"-1, a salti di "jump".
    Esempio: calcola e stampa la somma dei primi 20 numeri pari...

    In [16]:
    somma=0
    for i in range(2,21,2):
        somma=somma+i
    print(somma)
    
    110
    
    

    Notevole è la capacità di python di ciclare su due o più liste di numeri contemporaneamente prendendo i numeri a coppie (o triplette, ecc.) tramite la funzione zip(lista1, lista2, ecc.), che prende gli elementi delle varie liste uno ad uno e le restituisce come tuple.
    Esempio:

    In [4]:
    for a,b in zip([1,2,3],['a','b','c']):
        print(a, b)
    
    1 a
    2 b
    3 c
    
    

    Lo stesso effetto lo possiamo produrre ricordandoci che il metodo items di un dizionario produce una tupla chiave-valore.
    Esempio:

    In [19]:
    dieta={"Pasta": 350, "Carne": 200, "Uova": 80, "Frutta": 250}
    for tipo, calorie in dieta.items():
        print("100 gr di ", tipo, "contengono ", calorie, " calorie")
    
    100 gr di  Pasta contengono  350  calorie
    100 gr di  Frutta contengono  250  calorie
    100 gr di  Uova contengono  80  calorie
    100 gr di  Carne contengono  200  calorie
    
    

    Costrutto while

    Esegue ripetutamente un blocco di istruzioni fin tanto che una data condizione specificata sia verificata.
    while (condizione):
       ...
    

    Esempio: somma i primi numeri dispari tra 1 e 21...

    In [20]:
    x=1
    somma=0
    while ( x <= 21 ):
        somma=somma+x
        x=x+2
    print(somma)
    
    121
    
    

    Un esempio completo: il bubble-sort

    Algoritmo semplice di ordinamento di una lista di numeri: si cerca il minimo della lista e si mette al primo posto, quindi si cerca il minimo degli elementi successivi e si mette al secondo e così via...
    Esempio:

    In [22]:
    lista=[0.5, 0.8, 0.3, 1.2, 0.2, 0.1]
    print("Lista iniziale: ", lista)
    lungh=len(lista)    # Calcola la lunghezza della lista
    num_elem=0
    while ( num_elem < lungh ):
        # Cerca il minimo tra gli elementi restanti della lista
        xmin=lista[num_elem]
        xpos=num_elem
        for i in range(num_elem,lungh):
            if ( lista[i] < xmin ):
                xmin=lista[i]
                xpos=i
        print("Minimo fra gli elementi della lista fra ", num_elem, " e ", lungh - 1, ": ", xmin, " nella posizione: ", xpos)
        # Scambia il valore corrente nella lista con il minimo
        if ( num_elem != xpos ):
            temp=lista[num_elem]
            lista[num_elem]=xmin
            lista[xpos]=temp
        # Stampa la lista parzialmente ordinata
        print("Ordinamento parziale della lista: ", lista)
        num_elem=num_elem+1
    print("Lista finale ordinata: ", lista)
    
    Lista iniziale:  [0.5, 0.8, 0.3, 1.2, 0.2, 0.1]
    Minimo fra gli elementi della lista fra  0  e  5 :  0.1  nella posizione:  5
    Ordinamento parziale della lista:  [0.1, 0.8, 0.3, 1.2, 0.2, 0.5]
    Minimo fra gli elementi della lista fra  1  e  5 :  0.2  nella posizione:  4
    Ordinamento parziale della lista:  [0.1, 0.2, 0.3, 1.2, 0.8, 0.5]
    Minimo fra gli elementi della lista fra  2  e  5 :  0.3  nella posizione:  2
    Ordinamento parziale della lista:  [0.1, 0.2, 0.3, 1.2, 0.8, 0.5]
    Minimo fra gli elementi della lista fra  3  e  5 :  0.5  nella posizione:  5
    Ordinamento parziale della lista:  [0.1, 0.2, 0.3, 0.5, 0.8, 1.2]
    Minimo fra gli elementi della lista fra  4  e  5 :  0.8  nella posizione:  4
    Ordinamento parziale della lista:  [0.1, 0.2, 0.3, 0.5, 0.8, 1.2]
    Minimo fra gli elementi della lista fra  5  e  5 :  1.2  nella posizione:  5
    Ordinamento parziale della lista:  [0.1, 0.2, 0.3, 0.5, 0.8, 1.2]
    Lista finale ordinata:  [0.1, 0.2, 0.3, 0.5, 0.8, 1.2]
    
    

    Input-Output

    E' fondamentale che un programma possa ricevere dei valori di input da assegnare ad una variabile e stampi un risultato in output. Abbiamo già utilizzato l'istruzione print, nella sua forma più elementare, per stampare variabili, liste, ecc.
    L'istruzione:
    print(elem1, elem2, elem3, ecc., sep=" ", end="\n")

    stampa quindi un insieme di valori separati da virgole, dopo averli convertiti in stringhe. I parametri sep e end sono opzionali e indicano il separatore da utilizzare quando si hanno più variabili da stampare (default: uno spazio!) e come terminare la linea (default: new-line!).
    Nota python 2.7. In python 2.7.x print() NON è una funzione ma una istruzione. I dati da stampare NON devono perciò essere scritti tra parentesi!
    Esempio: (nota come, se anche non ci sono spazi tra "per", a, "di" gli spazi vengono inseriti per il valore di default di "sep", cioé lo spazio bianco!)

    In [26]:
    a=100
    print("Auguri per", a, "di questi giorni...")
    
    Auguri per 100 di questi giorni...
    
    

    L'istruzione print ritorna sempre accapo, a meno che si specifichi il flag: end=" ", per cui le stampe successive vengono accodate, separate da uno spazio, oppure un qualche altro valore.
    Nota python 2.7.x: in python 2.7 per evitare che l'istruzione print vada daccapo, occorre utilizzare la virgola: ,, come in: print "Ora non vado daccapo...", che scrive sulla stessa linea, separato con uno spazio, una successiva istruzione print.
    Esempio: stampa della tabellina...

    In [25]:
    for i in range(1,11):
        for j in range(1,11):
            print(i * j,end=" ")
        print()
    
    1 2 3 4 5 6 7 8 9 10 
    2 4 6 8 10 12 14 16 18 20 
    3 6 9 12 15 18 21 24 27 30 
    4 8 12 16 20 24 28 32 36 40 
    5 10 15 20 25 30 35 40 45 50 
    6 12 18 24 30 36 42 48 54 60 
    7 14 21 28 35 42 49 56 63 70 
    8 16 24 32 40 48 56 64 72 80 
    9 18 27 36 45 54 63 72 81 90 
    10 20 30 40 50 60 70 80 90 100 
    
    

    Operatore %

    L'operatore % serve a costruire una stringa in maniera da sostituire opportune sequenze di formato con i valori delle variabili.
    Esempio:

    In [27]:
    stringa="Ho mangiato %d uova e %d grammi di pasta..." % (3, 100)
    print(stringa)
    
    Ho mangiato 3 uova e 100 grammi di pasta...
    
    
    Le sequenze di formato stampabili sono:
    • %f: numero reale;
    • %e: numero reale in formato esponenziale (es. 1.e-3);
    • %d: numero intero;
    • %c: variabile carattere;
    • %s: variabile stringa;
    • %%: stampa il simbolo "%"

    Si possono utilizzare dei campi numerici fra il simbolo "%" ed il formato ("f", "d", ecc.) per delimitare l'ampiezza del campo di stampa!
    Esempio:

    In [28]:
    var=100
    print("Facciamo stare larghi i numeri: %10d" % var)
    
    Facciamo stare larghi i numeri:        100
    
    

    Un numero negativo allinea a sinistra, invece che a destra.
    Esempio: la tabellina di sopra, un po' più carina...

    In [29]:
    for i in range(1,11):
        for j in range(1,11):
            print("%-4d" % (i * j),end=" ")
        print()
    
    1    2    3    4    5    6    7    8    9    10   
    2    4    6    8    10   12   14   16   18   20   
    3    6    9    12   15   18   21   24   27   30   
    4    8    12   16   20   24   28   32   36   40   
    5    10   15   20   25   30   35   40   45   50   
    6    12   18   24   30   36   42   48   54   60   
    7    14   21   28   35   42   49   56   63   70   
    8    16   24   32   40   48   56   64   72   80   
    9    18   27   36   45   54   63   72   81   90   
    10   20   30   40   50   60   70   80   90   100  
    
    
    Nota python 2.7: l'analogo di questo script in python 2.7.x sarebbe:
    for i in range(1,11):
        for j in range(1,11):
            print "%-4d" % (i ∗ j),
        print
    
    Un simbolo
    *

    tra il "%" ed il formato indica una larghezza variabile che deve essere specificata tra le variabili.
    Esempio:

    In [4]:
    largh=10
    stringa1=">>>"
    stringa2="<<<"
    print("Ci troviamo a %*squesto%-*s punto!" % (largh, stringa1, largh, stringa2))
    
    Ci troviamo a        >>>questo<<<        punto!
    
    

    Funzione input(stringa)

    La funzione input serve per immettere un input da tastiera. Nota che la variabile immessa è sempre una stringa, quindi deve essere opportunamente convertita se si vuole un numero.
    Nota python 2.7.x: l'analoga funzione in python 2.7.x è: s = raw_input(stringa).
    Esempio: soluzione di una equazione di secondo grado...

    In [33]:
    print("Soluzione dell'equazione: a*x^2 + b*x + c = 0")
    a = input("Inserisci a: ")
    b = input("Inserisci b: ")
    c = input("Inserisci c: ")
    aa=float(a)
    bb=float(b)
    cc=float(c)
    print("Soluzioni:")
    print("x1 = ", (-bb+((bb*bb-4*aa*cc)**0.5))/(2*aa))
    print("x2 = ", (-bb-((bb*bb-4*aa*cc)**0.5))/(2*aa))
    
    Soluzione dell'equazione: a*x^2 + b*x + c = 0
    Inserisci a: 1.0
    Inserisci b: 2.0
    Inserisci c: -3.0
    Soluzioni:
    x1 =  1.0
    x2 =  -3.0
    
    

    Files

    Spesso occorre leggere dati in input da un file e/o scrivere risultati in output su un file.
    La prima operazione necessaria è dire al sistema che si vuole aprire un file, in lettura o in scrittura:
    oggetto = open( nome_file, metodo_di_accesso )
    
    dove:
    • nome_file: stringa contenente il nome del file;
    • metodo_di_accesso:
      • "r": lettura (read)
      • "w": scrittura (write)
      • "a": aggiunta in coda al file (append)

    Ultimate le operazioni di lettura/scrittura, il file può essere chiuso con il metodo close().
    Nota python 2.7.x: l'analogo della funzione open() in python 2.7.x è: file(), con gli identici parametri.
    Successivamente alla sua apertura, si possono leggere le righe da un file con il metodo readline(), che legge una intera stringa (incluso il newline!) dal file. Nota che se si arriva alla fine del file viene restituita la stringa vuota "".
    Esempio:

    In [36]:
    f=open("prova.dat","r")
    str=" "
    while str != "":
       str=f.readline()
       print(str,end="")
    f.close()
    
    Questo e' un esempio di file...
    Le righe vengono lette una alla volta
    e scritte sullo schermo...
    
    
    Nota il
    print(str,end="")

    senza il quale verrebbero stampate delle linee vuote perché "str" contiene il newline letto dal file

    Il metodo readlines() è più semplice in quanto produce una lista contenente tutte le linee del file.
    Esempio:

    In [38]:
    f=open("prova.dat","r")
    for linea in f.readlines():
       print(linea,end="")
    
    Questo e' un esempio di file...
    Le righe vengono lette una alla volta
    e scritte sullo schermo...
    
    

    Il metodo write(stringa) scrive una stringa su un file (nota che non è possibile scrivere numeri!).
    Esempio:

    In [39]:
    f=open("prova_out.dat","w")
    for i in range(10):
       f.write( "%d \t %f\n" % ( i+1, (i+1)**2.0 ) )
    f.close()
    

    Come leggere i dati appena scritti nel file?
    Conviene leggere i dati come stringhe e convertirli in numeri tramite le funzioni di conversione. Questa è la maniera più flessibile di leggere dati da un file. Come vedremo, la libreria numpy ha delle funzioni di semplice utilizzo per leggere direttamente i dati contenuti in un file, ma non sempre questo è sufficiente e per letture da files che sono stati scritti in maniera complicata conviene sempre utilizzare la lettura con le stringhe e la conversione.
    Esempio:

    In [40]:
    f=open("prova_out.dat","r")
    for stringa in f.readlines():
        vals=stringa.split("\t")
        i=int(vals[0])
        i2=float(vals[1])
        i3=i*i
        print(i, "\t", i2, "\t", i3)
    f.close()
    
    1 	 1.0 	 1
    2 	 4.0 	 4
    3 	 9.0 	 9
    4 	 16.0 	 16
    5 	 25.0 	 25
    6 	 36.0 	 36
    7 	 49.0 	 49
    8 	 64.0 	 64
    9 	 81.0 	 81
    10 	 100.0 	 100
    
    

    Le funzioni

    Abbiamo visto che è possibile utilizzare le funzioni tipiche del linguaggio dopo avere incluso i moduli che le contengono. Cioé un modulo è una raccolta di funzioni organizzate per soggetto. Possiamo noi stessi definire delle funzioni che ci consentono di eseguire azioni ripetitive a seconda degli argomenti con cui la funzione stessa viene chiamata e possiamo anche raggrupparle in un modulo scritto da noi, in modo da poterle includere e usarle all'occorrenza.
    Definizione di una funzione:
    def nome_funzione( parametri ):
        ...
        return parametro
    

    definisce una funzione con un nome, una lista di argomenti e che ritorna uno o più parametri.
    Nota che non è obbligatorio ritornare un valore!
    Esempio: definisce una funzione per calcolare il fattoriale di un numero...

    In [41]:
    def fact(n):
        if n == 1:
            return 1
        else:
            return n * fact(n-1)
    
    print(fact(4))
    print(fact(100))
    
    24
    93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
    
    

    E' possibile restituire più di un singolo valore, o anche nessun valore (nel qual caso la funzione esegue semplicemente delle operazioni in maniera ripetitiva per vari valori dei parametri.
    Esempio:

    In [42]:
    # Funzione che stampa una stringa n volte; NON ritorna valori
    def stampa_stringa(stringa,n):
        print(stringa * n,end="")
        print()
    
    stampa_stringa("Ciao!", 10)
    
    # Funzione che ritorna due liste, una con i numeri da 1 ad n, l'altra con i loro quadrati
    def doppia_lista(n):
        nums=range(n)
        lista1=[]
        lista2=[]
        for i in nums:
            lista1.append(i+1)
            lista2.append((i+1)**2.0)
        return lista1, lista2
    
    l1, l2 = doppia_lista(10)
    print(l1, l2)
    
    Ciao!Ciao!Ciao!Ciao!Ciao!Ciao!Ciao!Ciao!Ciao!Ciao!
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0, 81.0, 100.0]
    
    

    E' possibile definire delle funzioni con dei parametri opzionali, cioé dei valori che, se non specificati, assumono dei valori predefiniti, altrimenti il valore specificato.
    Esempio:

    In [44]:
    def stampa_stringa(stringa,n=1):
        print(stringa * n,end="")
        print()
    
    stampa_stringa("ok!")
    stampa_stringa("Ciao",10)
    
    ok!
    CiaoCiaoCiaoCiaoCiaoCiaoCiaoCiaoCiaoCiao
    
    

    E' anche possibile cambiare l'ordine dei parametri, purché si specifichi il parametro, il segno "=" ed il valore nella chiamata.
    Esempio:

    In [45]:
    stampa_stringa(n=5,stringa="Ok! ")
    
    Ok! Ok! Ok! Ok! Ok!