Fondamenti di Programmazione

Sequenze e Controllo

Stringhe

In Python, il testo si rappresenta come una una sequenza di caratteri che è chiamata stringa. Per rappresentare una stringa in Python basta racchiudere la sequenza di caratteri o tra apici singoli ' o tra doppi apici ":

>>> saluto = "ciao"

Usando i doppi apici possiamo usare all'interno della stringa gli apici singoli e viceversa.

>>> poesia = "M'illumino d'immenso"
>>> info = '"Mattina" di G. Ungaretti'

Si puo' indicare una stringa che non contiene nussun carattere semplicemente non includendo nulla tra gliu apici.

>>> stringa_vouta = ''

Se il testo prende più linee, possiamo racchiuderlo tra tre apici singoli ''' o tre doppi apici """ e possiamo anche usare liberamente singoli e doppi apici:

>>> versi = '''M'illumino
d'immenso
"Mattina" di G. Ungaretti'''
>>> print versi
M'illumino
d'immenso
"Mattina" di G. Ungaretti

Però se andiamo a visualizzare il valore della variabile versi

>>> versi
'M\'illumino\nd\'immenso\n"Mattina" di Giuseppe Ungaretti'

Il carattere che indica il fine linea non è stampabile e il carattere singolo apice non può essere usato in una stringa racchiusa tra singoli apici e allora questi caratteri e altri devono essere rappresentati con una sequenza d'escape:

Sequenza d'escape Descrizione
\n fine linea
\' singolo apice
\" doppio apice
\t tab
\\ backslash

Le stringhe possono essere concatenate con l'operatore +

>>> testo = poesia + ' - ' + info
>>> testo
'M\'illumino d\'immenso - "Mattina" di G. Ungaretti'
>>> print testo
M'illumino d'immenso - "Mattina" di G. Ungaretti

L'operatore + esegue operazioni differenti a seconda del tipo degli operandi: se sono numeri (int o float) esegue l'addizione e se sono stringhe (str) esegue la concatenazione. Nel gergo dei linguaggi di programmazione si dice che è un operatore overloaded. Se proviamo a usare l'operatore + con operandi misti

>>> 'numero' + 5
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    'numero' + 5
TypeError: cannot concatenate 'str' and 'int' objects

Se si vuole usare un numero come una stringa si può usare la funzione built-in str(). La funzione str(), come vedremo, può essere applicata a un valore di qualsiasi tipo, non solo un numero, e ritorna una stringa che è una rappresentazione stampabile del valore.

>>> x = 3.3
>>> str(5) + ' moltiplicato per ' + str(x) + ' fa ' + str(5*x)
'5 moltiplicato per 3.3 fa 16.5'

L'operatore * permette di ripetere una stringa. Gli operandi sono una stringa e un intero.

>>> boom = 'tic tac '*5 + 'BOOM!'
>>> boom
'tic tac tic tac tic tac tic tac tic tac BOOM!'

Visualizziamo un breve esempio.

s1 = 'Ciao'
s2 = 'Pippo'
s3 = s1 + ' ' + s2
s4 = s3 + ', '
s5 = s4 * 2 + s3

Liste

Come abbiamo già visto, per memorizzare dei valori possiamo usare le variabili, una per ogni valore. Ma se i valori sono tanti? Ad esempio, 100 nomi di studenti o centinaia valori di temperatura o migliaia di codici di prodotti. Introdurre una variabile per ogni valore sarebbe veramente tedioso se non impraticabile. Così in tutti i linguaggi di programmazione esistono tipi di dati che permettono di raggruppare insieme un gran numero di valori. Python ne ha diversi, il più comune e versatile è la lista che può essere scritto come un elenco di valori separati da virgole e racchiuso tra parentesi quadrate:

>>> primi = [2, 3, 5, 7, 11, 13, 17, 19]
>>> primi
[2, 3, 5, 7, 11, 13, 17, 19]
>>> colori = ['blu', 'rosso', 'verde', 'giallo', 'grigio']
>>> colori
['blu', 'rosso', 'verde', 'giallo', 'grigio']

Una lista può contenere valori di un qualsiasi tipo

>>> misc = ['red', 2, 3.14, 'blue']

Si puo' indicare una lista che non contiene nussun elemento semplicemente non includendo nulla tra le parentesi.

>>> lista_vouta = []

Inoltre, le operazioni + e * possono essere usate anche con le liste:

>>> primi2 = primi + [23, 29]
>>> primi2
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
>>> [1, 2, 3]*4
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

Questo non è un caso perché le stringhe e le liste appartengono alla famiglia più generale dei tipi sequenza che comprende anche altri tipi che incontreremo in seguito. Per tutti i tipi della famiglia delle sequenze si possono usare gli operatori +, * e altre operazioni.

Visualizziamo un piccolo esempio.

l1 = [1,2]
l2 = l1 + ['ciao']
l3 = l2 * 2

Elementi di una Sequenza

Per tutti i tipi della famiglia delle sequenze si possono usare gli indici per accedere agli elementi della sequenza. Ogni elemento in una lista è univocamente specificato dal suo indice, cioè il suo numero d'ordine a partire da zero nella lista. Per accedere ad un elemento si pone l'indice dell'elemento tra parentesi quadrate dopo un riferimento alla lista (ad esempio una variabile):

>>> primi[0]
2
>>> colori[1]
'rosso'
>>> misc[2]
3.14

La stessa sintassi è valida anche per le stringhe:

>>> stringa = 'abracadabra'
>>> stringa[2]
'r'

Se si accede ad un elemento non presente nella sequenza, si otterra' un errore.

>>> primi[10]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Ad esempio, la funzione built-in len() che ritorna la lunghezza della sequenza:

>>> len(primi2)
10
>>> len(stringa)
11

Immutabilità

C'è una differenza sostanziale tra le stringhe e le liste. Un stringa è immutabile mentre una lista è mutabile. Questo significa che una stringa una volta creata non può più essere modificata mentre una lista può sempre essere modificata. Ad esempio,

>>> primi2[2] = 100
>>> primi2
[2, 3, 100, 7, 11, 13, 17, 19, 23, 29]
>>> stringa[2] = 'R'
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    stringa[2] = 'R'
TypeError: 'str' object does not support item assignment

Iterazione

Le liste e più in generale le sequenze diventano veramente utili se possiamo elaborarle in modo iterativo specificando come deve essere elaborato un elemento "generico", evitando quindi di scrivere delle istruzioni esplicite per ogni elemento della sequenza. Per questo Python ha il costrutto for la cui sintassi generale è

for var in seq:
    istruzioni

Il ciclo for scorre i valori della sequenza seq, nell'odine, e ad ogni iterazione assegna alla variabile var il prossimo valore così che le istruzioni (indentate di 4 spazi) all'interno del for possano elaborare il valore. for e in sono parole chiavi. Ad esempio, se vogliamo stampare i valori di una lista, uno per linea:

colori = ['blu', 'rosso', 'verde', 'giallo', 'grigio']
for col in colori:
    print col

Spesso capita di dover iterare sugli indici di una lista, invece che sui valori. Se volessimo scrivere una variazione della funzione dell'esempio precedente in cui invece di creare una nuova lista vogliamo modificare la lista di input dovremmo iterare sugli indici per poter modificare i valori. Python ha una funzione built-in che è molto utile in questi casi. La funzione range() ritorna una lista che contiene una progressione aritmetica secondo i parametri di input:

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(5, 15)
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> range(1, 10, 2)
[1, 3, 5, 7, 9]

La funzione range() accetta dei parametri opzionali, con un solo parametro è la lunghezza (a partire a zero), con due parametri il primo è il valore iniziale e il secondo è il valore finale (escluso) e con tre parametri i primi due hanno la stessa interpretazione precedente e il terzo è l'incremento che di default è 1. Proviamo a fare un piccolo esempio:

r = range(1,10,2)
for i in r:
    print i

Funzioni sulle Liste

Il prossimo esempio è una funzione che prende in input una lista i cui valori si assume siano numeri, crea e ritorna una nuova lista i cui valori sono quelli della lista di input elevati al cubo:

def cubi(lst):
    '''Ritorna una nuova lista che contiene i cubi dei
    valori della lista di input lst.'''
    cubiLst = []
    for n in lst:
        cubiLst = cubiLst + [n**3]
    return cubiLst

primi = [2, 3, 5, 7, 11, 13]
cubi_primi = cubi(primi)
print primi
print cubi_primi

La stringa tra triplici apici (singoli o doppi) subito dopo il nome della funzione è la stringa che viene visualizzata quando si esegue l'help() della funzione ed appunto si chiama stringa di documentazione o docstring. È consigliabile scrivere sempre una breve spiegazione di cosa fa una funzione e quale è il significato dei parametri di input.

Adesso possiamo scrivere una variazione della funzione cubi() in cui modifichiamo la lista lst direttamente:

def setta_cubi(lst):
    """Modifica la lista di input lst elevando al
    cubo tutti i suoi valori e la ritorna."""
    for i in range(len(lst)):
        lst[i] = lst[i]**3
    return lst

primi = [2, 3, 5, 7, 11, 13]
print primi
setta_cubi(primi)
print primi

Scriviamo ora una funzione che prende in input un intero n e crea e ritorna una lista che contiene i cubi degli interi da 1 a n:

def crea_cubi(n):
    """Ritorna una lista che contiene i cubi degli interi da 1 a n."""
    lst = []
    for i in range(1, n + 1):
        lst += [i**3]
    return lst

lst = crea_cubi(10)
print lst

Un'altro esempio classico è una funzione che ritorna l'n-esimo numero di Fibonacci:

def fib(n):
    """Ritorna l'n-esimo numero di Fibonacci."""
    prev = 1
    curr = 0
    for i in range(n):
        p = curr
        curr += prev
        prev = p
    return curr

for i in range(10):
    print 'fib('+str(i)+') =', fib(i)