12: tuple E range

LA tuple

Oltre alle liste, esistono in Python altri tipi di dato derivati che hanno caratteristiche simili.

La tuple è anch'essa un insieme di oggetti. L'unica differenza con la lista è che essa non può più essere modificata una volta inizializzata, cioè i suoi elementi non possono più essere cambiati. Possiamo quindi leggerli, ma non scriverli, nè usare funzioni che la modificano, come append(), sort(). Si dice che la list è un oggetto mutable, mentre la tuple è immutable.

Per creare una tuple si scrivono i suoi elementi tra parentesi tonde. Proviamo con IDLE (ho commentato il codice per una migliore comprensione):


>>> citta = ("Roma", "Milano", "Napoli")   # una tuple di 3 stringhe
>>> len(citta)                             # ok, non sto cambiando la tuple

3

>>> citta[1]                               # ok, sto leggendo un valore

'Milano'

>>> citta[2] = "Torino"                    # errore, sto cercando di cambiare un valore

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    citta[2] = "Torino"
TypeError: 'tuple' object does not support item assignment

Probabilmente vi starete chiedendo: che bisogno c'è di un tipo di dato uguale alla lista, ma che fa meno cose? Il motivo è l'efficienza: ho già detto che la filosofia di Python è quella di nascondere il più possibile il lavoro che lui fa nella memoria del computer, in modo che il programmatore non se ne deva preoccupare. Tuttavia bisogna rendersi conto che maneggiare una lista è un'operazione molto gravosa dal punto di vista della gestione della memoria (dato che la lista può allungarsi e accorciarsi, Python non sa a priori quanto spazio essa occuperà, e quindi è costretto a cancellarla e riscriverla continuamente nella memoria del computer).

Usare una tuple è per Python molto più semplice: poichè non può più essere modificata richiede una quantità fissa di memoria e quindi meno tempo di elaborazione rispetto ad una lista. I programmatori esperti usano tipicamente le tuple quando è necessario creare delle tabelle di valori predefiniti che non varieranno più per tutto il programma e dalle quali ci sarà bisogno solo di leggere i dati.


>>> classe_prima_B = ("Abate", "Bartoli", "Concia")     #ecc.
>>> citta_lazio = ("Viterbo", "Latina", "Rieti", "Frosinone", "Roma")

Infine va detto che Python accetta una tuple anche senza scrivere le parentesi, semplicemente scrivendo i suoi elementi separati da virgole:


>>> numeri = 1, 2, 3, 4, 5
>>> type(numeri)

<class 'tuple'>

Questa doppia possibilità può disorientare i principianti, ma la segnalo ugualmente perchè si può trovare leggendo un programma scritto da altri. In particolare questa sintassi permette l'assegnazione multipla, usata molto spesso nel linguaggio perchè permette di "risparmiare" linee di codice:


a, b, c = 1, 2, 3

possiamo cioè assegnare in una sola istruzione più variabili: vengono prima calcolate tutte le espressioni a destra, poi vengono create due tuple temporanee e la tuple a destra è assegnata a quella a sinistra. A sinistra ci deve essere lo stesso numero di variabili delle espressioni a destra.

In ogni caso, data la facilità con cui ci si può confondere e generare errori inaspettati, consiglio per il momento di usare sempre le liste, lasciando la distinzione tra list e tuple a quando sarete più esperti.

IL range

Il range è ancora più semplice: è solo una sequenza di numeri interi, anch'essa unmutable. Può essere creato con la funzione range(), che ha tre sintassi possibili:

Funzione Significato
range(stop) I numeri da 0 a stop - 1 (stop non è mai compreso)
range(start, stop) I numeri da start (compreso) a stop (non compreso)
range(start, stop, step) I numeri a step a step partendo da start. step può essere anche negativo per ottenere un range di numeri decrescenti. L'ultimo numero è minore di start se step è positivo, maggiore se step è negarivo

Vediamo qualche esempio in IDLE:


>>> range(10)           # i numeri da 0 a 9
>>> range(-2)           # vuoto: stop e' < 0
>>> range(3, 12)        # i numeri da 3 a 11
>>> range(-6, 0)        # i numeri da -6 a -1
>>> range(-2, 13, 3)    # i numeri (-2, 1, 4, 7, 11) (fino all'ultimo numero < 13)
>>> range(10, 0, -1)    # i numeri decrescenti da 10 a 1 (0 non e' compreso)

Notate che nel caso del range IDLE vi risponde soltanto ripetendo range(10), ecc. senza farvi vedere gli elementi uno per uno. Anche la print() ha lo stesso comportamento.

CONVERSIONI

In ogni modo, le list, le tuple ed i range si possono convertire uno nell'altro mediante apposite funzioni di conversione (ma non si può convertire una list o tuple in un range).

Ad esempio, immaginiamo di avere bisogno di una lista con i primi 10000 numeri interi: scriverli uno per uno sarebbe decisamente seccante! Possiamo però facilmente ottenerli come range e poi trasformarlo in list


a = range(10000)
b = list(a)             # una list con 10000 elementi, impossibile da scrivere a mano
b = list(range(10000))  # meglio ancora: una sola istruzione

Provate adesso a chiedere ad IDLE il valore di b...

ESERCIZIO 12.1 Create mediante la funzione range() questi insiemi di numeri (per visualizzarli e controllare dovete convertirli in liste):
[ 1, 2, 3, 4, ... 100 ]
[ 2, 4, 6, 8, ... 200 ]
[ 1, 5, 9, 13, ... 1001 ]
[ 10, 8, 6, 4, 2, 0 ]
[ -1, -2, -3, -4, ... -10 ]
SOLUZIONI
ESERCIZIO 12.2 Scrivete in IDLE le seguenti espressioni booleane. Prima di dare Invio cercate di prevedere se il loro risultato è True o False
>>> 0 in range(20)
>>> 10 in range(20)
>>> 20 in range(20)
>>> 1 in range(1, 20)
>>> 2 in range(1, 20, 2)
>>> 19 in range(1, 20, 2)
>>> 5 in range(10, 1, -1)
>>> 2 in range(10, 1, -1)

Vedremo nella prossima lezione la notevole utilità dei range, soprattutto quando sono abbinati all'istruzione for.

GLI INDICI E LE STRINGHE

Il meccanismo degli indici funziona anche per le stringhe, per le quali possiamo indicare i singoli caratteri mediante la loro posizione nella stringa. Python restituirà una stringa formata dal solo carattere corrispondente. Ecco un esempio in IDLE;


>>> s = "Mamma mia!"
>>> s[0]

'M'

>>> s[4]

'a'

>>> s[5]

' '

>>> s[1] + s[9]

'a!'

Le stringhe sono comunque un tipo di dato immutable, quindi non è possibile usare gli indici per modificarle, nè, ovviamente, usare su di esse le funzioni proprie delle liste. Ricordiamo però che, al posto della append(), possiamo sempre usare la concatenazione (somma tra stringhe). continuate così:


>>> s[2] = "t"

Traceback (most recent call last):
  File "", line 1, in 
    s[2] = "t"
TypeError: 'str' object does not support item assignment

>>> s.append(10 *s[9])

Traceback (most recent call last):
  File "", line 1, in 
    s.append(10 * s[9])
AttributeError: 'str' object has no attribute 'append'

>>> s += (10 * s[9])
>>> s

'Mamma mia!!!!!!!!!!!'

Fine della lezione