Python
Python = è un linguaggio di programmazione:
- Interpretato
- Di alto livello
- Orientato agli oggetti
- Semplice da imparare e usare
- Potente e produttivo
- Ottimo anche come primo linguaggio (molto simile allo pseudocodice)
- Estensibile
- Con una tipizzazione forte e dinamica
Inoltre:
- È open source
- È multipiattaforma
- È facilmente integrabile con C/C++ e Java
Interprete interattivo del Python
Python dispone di un interprete interattivo molto comodo e potente. Per attivarlo possiamo digitare la parola python al prompt di una shell su un pc in cui è installato Python
Apparirà il simbolo >>> indicante che l’interprete è pronto a ricevere comandi
L'interprete è un file denominato:
- “python”su Unix
- “python.exe” su Windows > apre una console
- “pythonw.exe” su Windows > non apre una console
Se invocato senza argomenti presenta una interfaccia interattiva I comandi si possono inserire direttamente dallo standard input:
- Il prompt è caratterizzato da “ >>> ”
- Se un comando si estende sulla riga successiva è preceduto da “...”
I file sorgente Python sono file di testo, generalmente con estensione “.py
Introducendo “#! /usr/bin/env python” come prima riga su Unix il sorgente viene eseguito senza dover manualmente invocare l’interprete. Il simbolo “#” inizia un commento che si estende fino a fine riga. Le istruzioni sono separate dal fine riga e non da “ ; ”
- Il “ ; ” può comunque essere usato per separare istruzioni sulla stessa riga, ma è sconsigliato
Per far continuare un’istruzione anche sulla linea successiva è necessario inserire il simbolo “\” a fine riga
Se le parentesi non sono state chiuse, l’istruzione si estende anche sulla riga successiva
L’interprete interattivo è in grado di leggere e valutare man mano le espressioni inserite dall’utente, ma è anche possibile eseguire script contenenti sequenze di istruzioni Python, digitando il comando:
python script.py
Ogni volta che viene invocato il comando python, il codice scritto viene scansionato per token, ognuno dei quali viene analizzato dentro una struttura logica ad albero che rappresenta il programma.
Token = è un blocco di testo categorizzato, normalmente costituito da caratteri indivisibili.
Tale struttura viene, infine, trasformata in bytecode (file con estensione .pyc o .pyo). Per potere eseguire questi bytecode, si utilizza un apposito interprete noto come macchina virtuale Python (PVM).
Variabili e istruzione di assegnamento: sintassi
Sintassi: variabile = espressione
- non devono esserci spazi prima del nome della variabile
- variabile deve essere un nome simbolico scelto dal programmatore (con le limitazioni descritte più avanti)
- espressione indica il valore (per es., un numero) che si vuole associare alla variabile
Limitazioni sui nomi delle variabili
1) possono essere composti da uno o più dei seguenti caratteri:
- lettere minuscole e maiuscole (NB: «A» e «a» sono considerate lettere diverse)
- cifre
- il carattere _ (underscore)
2) non devono iniziare con una cifra
3) non devono contenere simboli matematici (+, -, /, *, parentheses)
4) non devono coincidere con le keywords del linguaggio
Un nome di variabile può avere fino ad un massimo di 256 caratteri totali
Tipi di dato ed espressioni
I tipi di dato base che possono essere rappresentati ed elaborati dai programmi Python, sono:
- numeri interi
- numeri frazionari (floating-point)
- stringhe di caratteri
- booleani
Le espressioni Python che producono valori appartenenti a tali tipi di dati, e che possono contenere opportuni operatori, sono le seguenti:
- espressioni aritmetiche
- espressioni stringa
Espressioni aritmetiche
La più semplice espressione aritmetica è un singolo numero. I numeri vengono rappresentati nelle istruzioni Python con diverse notazioni, simili a quelle matematiche, espressi in base dieci. Python distingue tra due tipi di dati numerici:
- numeri interi, codificati nei calcolatori in complemento a due
- numeri frazionari (floating point), codificati in virgola mobile, e rappresentati nei programmi:
+ come parte intera e frazionaria, separate da un punto
+ in notazione esponenziale
Operatori aritmetici
Espressione aritmetiche più complesse si ottengono combinando numeri attraverso operatori (addizione, divisione, ecc.), e usando le parentesi tonde per definire la precedenza tra gli operatori.
Gli operatori disponibili nel linguaggio Python sono i seguenti:
Espressioni: stringhe
Stringhe = sequenze di caratteri (lettere, numeri, segni di punteggiatura) racchiuse tra apici singoli o doppi.
Le stringhe possono essere elaborate dai programmi Python
Concatenazione di stringhe
Il linguaggio Python prevede alcuni operatori anche per il tipo di dato stringa. Uno di questi è l'operatore di concatenazione, che si rappresenta con il simbolo + (lo stesso dell’addizione tra numeri) e produce come risultato una nuova stringa ottenuta concatenando due altre stringhe.
Sequenze di escape
Una espressione contenente il nome di una variabile alla quale non sia stato ancora assegnato alcun valore è sintatticamente errata.
La funzione input()
La funzione built-in input può essere utilizzata in due forme. valore = input() l’interprete resta in attesa che l’utente inserisca nella shell, attraverso la tastiera, una sequenza di caratteri che dovrà essere conclusa dal tasto .Questa sequenza di caratteri è poi inserita in una stringa che viene restituita come valore.
dato = input(messaggio)
l’interprete stampa messaggio, che deve essere una stringa, nella shell, poi procede come indicato sopra. La stringa messaggio viene di norma usata per indicare all’utente che il programma è in attesa di ricevere un particolare dato in ingresso.
Nel caso di dati numerici, occorrerà convertire con int o float intero o frazionario il valore str restituito da input.
La funzione print Sintassi
print (espressione):
- non devono esserci spazi prima di print
- espressione deve essere una espressione valida del linguaggio Python
Semantica: viene mostrato sullo standard output il valore di espressione
È anche possibile mostrare con una sola istruzione print i valori di un numero qualsiasi di espressioni, con la seguente sintassi:
print (espressione1, espressione2, ...)
In questo caso, i valori delle espressioni vengono mostrati su una stessa riga, separati da un carattere di spaziatura.
Commenti
È sempre utile documentare i programmi inserendo commenti che indichino quale operazione viene svolta dal programma, quali sono i dati di ingresso e i risultati, qual è il significato delle variabili o di alcune sequenze di istruzioni.
Nei programmi Python i commenti possono essere inseriti in qualsiasi riga, preceduti dal carattere # (“cancelletto”).
Tutti i caratteri che seguono il cancelletto, fino al termine della riga, saranno considerati commenti e verranno trascurati dall’interprete.
Errori a runtime
Un exception error si verifica se si utilizza un operatore con tipi di dato non compatibili
La funzione type
Python ha una funzione built-in denominata type che può essere usata per ottenere il tipo di ogni variabile o valore costante.
Espressioni condizionali
Sintassi: espressione1 operatore espressione2
- espressione1 e espressione2 sono due espressioni Python qualsiasi, definite come si è visto in precedenza (possono quindi contenere nomi di variabili, purché a tali variabili sia stato già assegnato un valore)
– operatore è un simbolo che indica il tipo di confronto tra le due espressioni
Operatori di confronto
Nel linguaggio Python sono disponibili i seguenti operatori di confronto, che possono essere usati sia su espressioni aritmetiche che su espressioni composte da stringhe:
Espressioni condizionali composte
Sintassi:
- espr_cond_1 and espr_cond_2
- espr_cond_1 or espr_cond_2
- not espr_cond
espr_cond_1, espr_cond_2 e espr_cond sono espressioni condizionali qualsiasi (quindi, possono essere a loro volta espressioni composte).
Gli operatori and, or e not sono detti operatori logici, e corrispondono rispettivamente ai connettivi logici del linguaggio naturale “e”, “oppure”, “non”
É possibile usare le parentesi tonde per definire l'ordine degli operatori logici
L’istruzione condizionale
Sintassi:
if espr_cond:
sequenza_di_istruzioni_1
else:
sequenza_di_istruzioni_2
- le keyword if e else devono avere lo stesso rientro
- espr_cond è un'espressione condizionale
- sequenza_di_istruzioni_1 e sequenza_di_istruzioni_2 sono due sequenze di una o più istruzioni qualsiasi
- ciascuna istruzione deve essere scritta in una riga distinta, con un rientro di almeno un carattere; il rientro deve essere identico per tutte le istruzioni
L’istruzione condizionale: varianti
Variante if:
if espr_cond:
sequenza_di_istruzioni
Variante elif:
if espr_cond_1:
sequenza_di_istruzioni_1
elif espr_cond_2:
sequenza_di_istruzioni_2
else:
sequenza_di_istruzioni_3
I rientri sono l’unico elemento sintattico che indica quali istruzioni fanno parte di un'istruzione condizionale. Le istruzioni che seguono un'istruzione condizionale (senza farne parte) devono quindi essere scritte senza rientri.
Come esempio, si considerino le due sequenze di istruzioni:
Nella sequenza a sinistra le due istruzioni print sono scritte con un rientro rispetto a if: questo significa che fanno entrambe parte dell’istruzione condizionale e quindi verranno eseguite solo se la condizione x > 0 sarà vera. Nella sequenza a destra solo la prima istruzione print dopo if è scritta con un rientro e quindi solo essa fa parte dell’istruzione condizionale; la seconda istruzione print verrà invece eseguita dopo l’istruzione condizionale, indipendentemente dal valore di verità della condizione x > 0
Istruzioni condizionali annidate
Una istruzione condizionale può contenere al suo interno istruzioni qualsiasi, quindi anche altre istruzioni condizionali. Si parla, in questo caso, di istruzioni annidate. L’uso di istruzioni condizionali annidate consente di esprimere la scelta tra più di due sequenze di istruzioni alternative. Una istruzione condizionale annidata all’interno di un'altra andrà scritta tenendo conto che:
- le keyword if, elif e else (se presenti) devono essere scritte con un rientro rispetto a quelle dell'istruzione condizionale che le contiene
- le sequenze di istruzioni che seguono if, elif e else devono essere scritte con un ulteriore rientro
Funzioni built-in
Le funzioni disponibili in un linguaggio di programmazione sono dette predefinite, o built-in. Libreria = insieme di tali funzioni.
Chiamata di funzione
Sintassi: nome_funzione(arg1, arg2, ..., argn)
- arg1, arg2, ..., argn sono espressioni Python i cui valori costituiranno gli argomenti della funzione
- il numero degli argomenti e il tipo di ciascuno di essi (per es., numeri interi, numeri frazionari, stringhe, valori logici) dipende dalla specifica funzione; se il tipo di un argomento non è tra quelli previsti, si otterrà un messaggio d’errore
- come tutte le espressioni, anche la chiamata di una funzione produce un valore: questo coincide con il valore restituito dalla funzione
Argomenti di funzione
Gli argomenti di una chiamata di funzione sono costituiti da espressioni. In ciascuno degli argomenti può quindi comparire un'espressione Python qualsiasi, purché produca un valore di un tipo previsto dalla funzione (in caso contrario si otterrà un messaggio d'errore). Ne consegue, come caso particolare, che una chiamata di funzione può contenere tra le espressioni dei suoi argomenti altre chiamate di funzioni (chiamate annidate).
Principali funzioni della libreria math
Tutte le funzioni di questa libreria restituiscono un numero frazionario.
La libreria random
Ogni chiamata di tali funzioni produce un numero pseudo-casuale, indipendente (in teoria) dai valori prodotti dalle chiamate precedenti.
From import
Per poter chiamare una funzione di librerie come math e random è necessario utilizzare la combinazione from import
Sintassi: from nome_libreria import nome_funzione
- nome_libreria è il nome simbolico di una libreria
- nome_funzione può essere:
+ il nome di una specifica funzione di tale libreria (questo consentirà di usare solo tale funzione)
+ il simbolo * indicante tutte le funzioni di tale libreria
Se la combinazione from import non viene usata correttamente, la chiamata di funzione produrrà un errore.
Costanti matematiche
Oltre a varie funzioni, nella libreria math sono definite due variabili che contengono il valore (approssimato) delle costanti matematiche π (3,14. . . ) ed e (la base dei logaritmi naturali: 2,71. . . ):
- pi
- e
Per usare queste costanti è necessaria la combinazione from import, in una delle due versioni:
- from math import *
- from math import nome_variabile dove nome_variabile dovrà essere pi oppure e
Definizione di nuove funzioni
Oltre ad usare le funzioni predefinite, è possibile creare nuove funzioni. La definizione di una nuova funzione è composta dai seguenti elementi:
- il nome della funzione
- il numero dei suoi argomenti
- la sequenza di istruzioni, detta corpo della funzione, che dovranno essere eseguite quando la funzione sarà chiamata
La definizione di una nuova funzione avviene attraverso l’uso della keyword def
Def
Sintassi: def nome_funzione (par1, ..., parn):
corpo_della_funzione
- nome_funzione è un nome simbolico scelto dal programmatore, con gli stessi vincoli a cui sono soggetti i nomi delle variabili
- par1, ..., parn sono nomi (scelti dal programmatore) di variabili, dette parametri della funzione, alle quali l'interprete assegnerà i valori degli argomenti che verranno indicati nella chiamata della funzione
- corpo_della_funzione è una sequenza di una o più istruzioni qualsiasi, ciascuna scritta in una riga distinta, con un rientro di almeno un carattere, identico per tutte le istruzioni
La prima riga della definizione (contenente i nomi della funzione e dei parametri) è detta intestazione della funzione.
Return
Per concludere l'esecuzione di una funzione e indicare il valore che la funzione dovrà restituire come risultato della sua chiamata si usa l’istruzione return.
Sintassi: return espressione
dove espressione è un'espressione Python qualsiasi.
L’istruzione return può essere usata solo all’interno di una funzione.
Se una funzione non deve restituire alcun valore:
- l’istruzione return può essere usata, senza l’indicazione di alcuna espressione, per concludere l'esecuzione della funzione
- se non si usa l’istruzione return, l’esecuzione della funzione terminerà dopo l'esecuzione dell'ultima istruzione del corpo
Definizione e chiamata di una funzione
L'esecuzione dell'istruzione def non comporta l'esecuzione delle istruzioni della funzione: tali istruzioni verranno eseguite solo attraverso una chiamata della funzione. L'istruzione def dovrà essere eseguita una sola volta, prima di qualsiasi chiamata della funzione. In caso contrario, il nome della funzione non sarà riconosciuto dall'inteprete e la chiamata produrrà un messaggio di errore.
Esecuzione della chiamata di funzione
L'interprete esegue la chiamata di una funzione nel modo seguente:
1. copia il valore di ciascun argomento nel parametro corrispondente (quindi tali variabili possiedono già un valore nel momento in cui inizia l'esecuzione della funzione)
2. esegue le istruzioni del corpo della funzione, fino all'istruzione return oppure fino all'ultima istruzione del corpo
3. se l'eventuale istruzione return è seguita da un'espressione, restituisce il valore di tale espressione come risultato della chiamata
While
Sintassi: while espr_cond:
sequenza_di_istruzioni
- la keyword while deve essere scritta senza rientri
- espr_cond è una espressione condizionale qualsiasi
- sequenza_di_istruzioni consiste in una o più istruzioni qualsiasi. Ciascuna di tali istruzioni deve essere scritta in una riga distinta, con un rientro di almeno un carattere. Il rientro deve essere identico per tutte le istruzioni della sequenza
Massimo comun divisore
Calcolo del massimo comun divisore con l’algoritmo di Euclide
Serie armonica
Calcolo della somma dei primi m termini della serie armonica:
Chiamate di funzioni all’interno di altre funzioni
Nelle istruzioni del corpo di una funzione possono comparire chiamate di altre funzioni, sia predefinite che definite dall'utente. Se si vuole chiamare una funzione predefinita appartenente a una delle librerie Python (come math o random) sarà necessario inserire prima della chiamata la corrispondente combinazione from import from import viene di norma inserita all'inizio del file che contiene il codice.
Chiamare funzioni all’esterno
Per poter chiamare dall’interno di una funzione un'altra funzione definita dall'utente sono disponibili due alternative:
1. la definizione delle due funzioni deve trovarsi nello stesso file
2. le due funzioni possono essere definite in file diversi, ma tali file dovranno trovarsi in una stessa cartella e nel file che contiene la chiamata dell'altra funzione si dovrà inserire l'istruzione from nomefile import nomefunzione dove:
- nomefile è il nome del file che contiene la definizione dell'altra funzione (senza l'estensione .py)
- nomefunzione è il nome di tale funzione
Variabili locali
I parametri di una funzione e le eventuali altre variabili alle quali viene assegnato un valore all'interno di essa sono dette locali, cioè vengono create dall’interprete nel momento in cui la funzione viene eseguita (con una chiamata) e vengono distrutte quando l'esecuzione della funzione termina.
Variabili globali
Se invece all’interno di una funzione il nome di una variabile (che non sia uno dei parametri) compare in una espressione senza che in precedenza nella funzione sia stato assegnato a essa alcun valore, tale variabile è considerata globale, cioè l’interprete assume che il suo valore sia stato definito nelle istruzioni precedenti la chiamata della funzione. In questo modo, le istruzioni di una funzione possono accedere al valore di variabile definita nel programma chiamante (se tale variabile non esiste si ottiene un messaggio di errore). In generale, è preferibile evitare l’uso di variabili globali nelle funzioni, poiché la loro presenza rende più difficile assicurare la correttezza di un programma.
Tipi semplici e strutturati
I tipi di dato possono essere classificati in:
1. tipi semplici
2. tipi strutturati
Tipo semplice = è composto da valori che non possono essere “scomposti” in valori più
semplici ai quali sia possibile accedere attraverso operatori o funzioni del linguaggio.
Esempi di tipi semplici del linguaggio Python (e di altri linguaggi) sono i numeri interi, i
numeri frazionari e i valori Booleani.
Tipo strutturato = è invece composto da valori che sono a loro volta collezioni o sequenze
di valori più semplici.
Le stringhe sono un esempio di tipo strutturato: sono infatti composte da sequenze
ordinate di caratteri a cui è possibile accedere individualmente.
Tipi di dato strutturati di Python
Oltre alle stringhe, due dei principali tipi strutturati del linguaggio Python sono:
1. le liste, che consentono di rappresentare sequenze ordinate di valori qualsiasi
2. i dizionari, che consentono di rappresentare collezioni (non ordinate) di valori qualsiasi Esistono anche altri tipi di dato strutturati (come le tuple) ed è possibile definirne di nuovi.
Il tipo di dato list
Le coordinate di un punto in un dato sistema di riferimento possono essere rappresentate come una sequenza ordinata di numeri reali. Per rappresentare in modo compatto le coordinate di un punto in uno spazio a tre dimensioni può essere utilizzata una singola variabile di tipo list invece che tre variabili distinte di tipo float. Il tipo list fornisce questa possibilità per sequenze ordinate di valori che possono appartenente a tipi qualsiasi, anche diversi tra loro.
Rappresentazione list
Una lista si rappresenta nei programmi Python come: 9 una sequenza ordinata di valori 9 scritti tra parentesi quadre 9 separati da virgole
Il tipo di dato list
Le liste, come i valori di qualsiasi tipo di dato Python, sono espressioni e possono quindi essere scritte in qualsiasi punto di un programma nel quale possa comparire una espressione. È possibile:
- stampare una lista con l’istruzione print, per esempio:
print ([7, -2, 4])
- assegnare una lista a una variabile, per esempio:
v = [7, -2, 4]
Valori degli elementi di una list
I valori degli elementi di una lista possono a loro volta essere indicati attraverso espressioni.
List annidate
Poiché gli elementi di una lista possono essere valori di un tipo qualsiasi, possono a loro volta essere liste. Si parla in questo caso di liste annidate, esattamente come nel caso di istruzioni composte (condizionale e iterativa) che contengano al loro interno altre istruzioni composte.
Accesso agli elementi di una list
Il linguaggio Python mette a disposizione dei programmatori diversi operatori e funzioni predefinite per le liste. In particolare, essendo le liste un tipo strutturato, alcuni operatori consentono l'accesso ai singoli elementi di una lista. Il meccanismo di accesso si basa sul fatto che ogni elemento è identificato univocamente dalla sua posizione all'interno di una lista (si ricordi che una lista è una sequenza ordinata di valori). La posizione di ciascun elemento di una lista è rappresentata in linguaggio Python attraverso un numero intero, detto indice. Per convenzione, l’indice del primo elemento di una lista è 0, l'indice del secondo elemento è 1 e così via.
Principali operatori list
Operatori di confronto
Gli operatori == e != consentono di scrivere espressioni condizionali (il cui valore sarà True o False) consistenti nel confronto tra due liste.
Sintassi:
lista_1 == lista_2
lista_1 != lista_2
dove lista_1 e lista_2 indicano espressioni che abbiano come valore una lista.
Semantica = due liste sono considerate identiche se sono composte dallo stesso numero di elementi e se ogni elemento ha valore identico a quello dell'elemento che si trova nella stessa posizione nell'altra lista.
Gli operatori in e not in
Gli operatori in e not in consentono di scrivere espressioni condizionali che hanno lo scopo di verificare se un certo valore sia presente o meno all’interno di una lista.
Sintassi = espressione in lista espressione not in lista dove espressione indica una qualsiasi espressione Python
Semantica = se il valore di espressione è presente tra gli elementi di lista, allora l'operatore in restituisce il valore True; in caso contrario, restituisce False. Il comportamento dell'operatore not in è l’opposto di quello per in. La ricerca non viene estesa agli elementi di eventuali liste annidate all'interno di lista.
L’operatore di concatenazione
L’operatore di concatenazione per le liste è analogo al corrispondente operatore del tipo di dato stringa
Sintassi = lista_1 + lista_2
Semantica = la concatenazione restituisce una nuova lista composta dagli elementi di lista_1 seguiti da quelli di lista_2, disposti nello stesso ordine in cui si trovano nelle due liste. Le liste originali non vengono modificate.
L’operatore di indicizzazione
L'operatore di indicizzazione consente di accedere a ogni singolo elemento di una lista, per mezzo dell'indice corrispondente.
Sintassi = lista[indice] dove indice deve essere un'espressione il cui valore sia un intero compreso tra 0 e la lunghezza della lista meno uno.
Semantica = il risultato è il valore dell'elemento di lista il cui indice è pari al valore di indice. Se il valore di indice non corrisponde a una delle posizioni della lista si otterrà un messaggio di errore.
Indici negativi per list
L’indice -1 indica l’ultimo elemento della lista, -2 il penultimo e così via
Modifica degli elementi di una list
L'operatore di indicizzazione consente anche di modificare i singoli elementi di una lista, attraverso una istruzione di assegnamento.
Sintassi: lista[indice] = espressione dove lista indica il nome di una variabile alla quale sia stata in precedenza assegnata una lista, mentre espressione indica una qualsiasi espressione Python
Semantica = l’elemento di lista nella posizione corrispondente a indice viene sostituito dal valore di espressione.
L’operatore di slicing
L’operatore di slicing restituisce una lista composta da una sottosequenza della lista a cui viene applicato.
Sintassi = lista[indice_1:indice_2] dove indice_1 e indice_2 sono espressioni i cui valori devono essere numeri interi compresi tra 0 e la lunghezza di lista.
Semantica = il risultato è una lista composta dagli elementi di lista aventi indici da indice_1 a indice_2 − 1 (si noti che l'elemento avente indice pari a indice_2 non viene incluso nel risultato). Anche in questo caso la lista originale non viene modificata.
Funzioni built-in per le list
Sequenze
Le stringhe e le liste sono tipi di dato che hanno in comune il fatto di essere costituite da sequenze ordinate di un numero qualsiasi di elementi. Per questo motivo sono entrambe indicate in linguaggio Python con il termine più generale di sequenze. Alcuni operatori e alcune funzioni built-in che operano su sequenze ordinate possono essere applicati sia alle liste che alle stringhe:
- funzioni built-in: len
- operatori: in e not in, indicizzazione, slicing, concatenazione
Liste vs stringhe
Liste e stringhe presentano una importante differenza. Mentre attraverso l’istruzione di assegnamento e l’operatore di indicizzazione è possibile modificare i singoli elementi di una lista, non è invece possibile modificare i singoli caratteri delle stringhe. Per tale motivo:
- le liste sono dette sequenze mutabili
- le stringhe sono dette sequenze immutabili > il tentativo di modificare un elemento di una stringa produce un errore!
Accesso agli elementi di liste annidate
Gli elementi di una lista possono essere valori di tipi qualsiasi, quindi anche strutturati, come stringhe o altre liste. L’operatore di indicizzazione consente di accedere anche agli elementi di strutture annidate. Se s è una variabile a cui è stata assegnata una lista e l’elemento di indice i della lista è a sua volta una sequenza (lista o stringa), sarà possibile accedere all’elemento di indice j di quest’ultima con la seguente sintassi: s[i][j]
Matrici
Una matrice di m righe e n colonne può essere rappresentata in un programma Python in diversi modi. Una possibilità consiste nel memorizzare i suoi elementi, in un ordine opportuno, in una lista “semplice” (non annidata) di m × n elementi.
Si consideri per esempio la seguente matrice:
essa può essere rappresentata dalla lista: [-3, 1, 4, 2, 5, -1]
Matrici come liste annidate
La matrice considerata in precedenza può essere rappresentata dalla seguente lista nidificata: [[-3, 1, 4], [2, 5, -1]] Assumendo che tale lista sia stata assegnata a una variabile di nome M, per accedere all’elemento nella seconda riga (i = 2) e nella prima colonna (j = 1) si userà l’espressione M[1][0]
Stampa di una matrice
L’istruzione iterativa for
Python include una versione alternativa dell'istruzione iterativa while: l'istruzione for. L’istruzione for consente di esprimere un solo tipo di iterazione che consiste nell'accedere a tutti gli elementi di una sequenza (stringa o lista). L’accesso avviene dal primo all'ultimo elemento e non è possibile modificare tale ordine
for: sintassi
- v è il nome di una variabile
- è una espressione avente come valore una sequenza (una lista o una stringa)
- sequenza_di_istruzioni è una sequenza di una o più istruzioni qualsiasi, che devono rispettare la regola sui rientri già vista per l’istruzione while
Confronto tra while e for
Non è possibile usare l'istruzione for con lo schema visto in precedenza per eseguire operazioni sugli elementi di una sequenza che richiedano l'uso esplicito degli indici, come per esempio:
- la modifica di un elemento di una lista attraverso una istruzione di assegnamento lista[k] = valore
- l'accesso a più di un elemento di una lista o di una stringa, per esempio per confrontare i valori di due elementi adiacenti con una espressione condizionale come la seguente: lista[k] != lista[k + 1]
Il ciclo while seguente assegna il valore 0 a tutti gli elementi di una lista precedentemente memorizzata in una variabile di nome lista:
Se invece si usasse una sequenza di istruzioni come:
la lista non verrebbe modificata, poiché la variabile elemento contiene solo una copia del valore di ciascun elemento della lista
Funzione enumerate
Grazie alla funzione enumerate è possibile usare l'istruzione for per accedere agli elementi di una sequenza usando una variabile come indice.
Metodo split
La funzione della classe string denominata split è molto utile per l'elaborazione di stringhe Sintassi = stringa.split() dove stringa indica una variabile avente per valore una stringa.
La funzione split suddivide una stringa in corrispondenza dei caratteri di spaziatura (incluso il newline) e restituisce le corrispondenti sottostringhe all'interno di una lista, senza includere i caratteri di spaziatura. La stringa originale non viene modificata.
Metodo split per dati formattati
Se si desidera suddividere una stringa in corrispondenza di una sequenza di uno o più caratteri specifici, tale sequenza dovrà essere indicata (sotto forma di una stringa) come argomento di split
Sintassi = stringa.split (caratteri)
Tipi di dato strutturati di Python
Oltre alle stringhe, due dei principali tipi strutturati del linguaggio Python sono:
1. le liste, che consentono di rappresentare sequenze ordinate di valori qualsiasi
2. i dizionari, che consentono di rappresentare collezioni (non ordinate) di valori qualsiasi Esistono anche altri tipi di dato strutturati (come le tuple) ed è possibile definirne di nuovi.
Tipo di dato dizionario
Le liste consentono di rappresentare dati strutturati i cui valori siano composti da una sequenza ordinata di valori più semplici. Un altro caso comune nella pratica è quello in cui i valori dei dati da elaborare siano rappresentabili come collezioni (insiemi) di valori più semplici e non ordinati, ciascuno dei quali abbia un significato che possa essere descritto con un nome simbolico. Un esempio sono le informazioni anagrafiche su uno studente: nome, cognome, data e luogo di nascita, codice fiscale, matricola, ecc. I dati aventi tali caratteristiche possono essere rappresentati in Python per mezzo del tipo strutturato dizionario.
Il tipo di dato dizionario è costituito da collezioni:
- non ordinate
- modificabili
- indicizzate aventi di un numero qualsiasi di valori, ciascuno dei quali può appartenere a qualsiasi tipo di dato.
Ognuno di tali valori è associato ad un identificatore univoco detto chiave, che di norma è una stringa, che deve essere scelto dal programmatore.
Come per le variabili e i nomi delle funzioni, anche per le chiavi dei dizionari è buona norma usare stringhe mnemoniche. Un dizionario è quindi un insieme di coppie chiave/valore. In particolare, all’interno di un dizionario:
- non possono esistere chiavi identiche
- ogni elemento (coppia chiave/valore) è identificato univocamente dalla sua chiave
- tra gli elementi non è definito alcun ordinamento
Tipo di dato dizionario: sintassi
Un dizionario si rappresenta nei programmi Python come una sequenza di elementi
- racchiusi tra parentesi graffe
- separati da virgole
Ogni elemento è costituito da una coppia chiave/valore, in cui i due elementi di ogni coppia sono separati da due punti.
Tipo di dato dizionario: esempi
In un dizionario che contiene informazioni anagrafiche su una persona relative a nome e cognome (i cui valori sono stringhe) ed età (il cui valore è un numero intero), le chiavi saranno le stringhe "nome", "cognome", "età":
{"nome":"Maria", "cognome":"Bianchi", "eta":28}
Per un dizionario che contiene le coordinate di un punto (due numeri frazionari) nel piano cartesiano, associate alle chiavi ‘x’ e ’y’, avremo:
{'x':-1.2, 'y':3.4}
Un dizionario che contiene una data (giorno, mese e anno, in formato numerico):
{"giorno":1, "mese":6, "anno": 2017}
un dizionario vuoto: {}
Il tipo di dato dictionary
Anche i valori di tipo dizionario costituiscono espressioni Python. È quindi possibile:
- stampare un dizionario con l’istruzione print, per esempio:
print({'x':-1.2, 'y':3.4})
- assegnare un dizionario a una variabile, per esempio:
punto = {'x':-1.2, 'y':3.4}
Nota: quando un dizionario viene stampato, le coppie chiave/valore compaiono in un ordine che non può essere controllato dal programmatore.
Espressioni in dizionari
I valori di ogni elemento di un dizionario possono essere indicati attraverso espressioni.
Per esempio, dopo l’esecuzione della seguente sequenza di istruzioni:
la variabile persona sarà associata al seguente dizionario:
Dizionari annidati
Come per le liste, anche gli elementi di un dizionario possono contenere valori di tipo qualsiasi e quindi anche valori strutturati come stringhe, liste e dizionari (annidati).
Per esempio, il dizionario seguente (non annidato) contiene il nome, il cognome e la data di nascita di una persona (giorno, mese e anno in formato numerico):
Le stesse informazioni possono essere memorizzate in due dizionari annidati:
Principali operatori per i dizionari
Operatori di confronto
Gli operatori == e != consentono di scrivere espressioni condizionali (il cui valore sarà True o False) consistenti nel confronto tra due dizionari.
Sintassi: dizionario_1 == dizionario_2 dizionario_1 != dizionario_2 dove dizionario_1 e dizionario_2 indicano espressioni aventi come valore un dizionario.
Semantica: due dizionari sono considerati identici se contengono le stesse coppie chiave/valore, indipendentemente dal loro ordine.
L’operatore di indicizzazione
L'operatore di indicizzazione consente di accedere al valore di ogni elemento di un dizionario, per mezzo della chiave corrispondente.
Sintassi: dizionario[chiave]
- dizionario deve essere una espressione che restituisce un dizionario
- chiave deve essere una espressione il cui valore corrisponde a una delle chiavi del dizionario
Semantica: viene restituito il valore dell'elemento di dizionario associato a chiave. Se il valore di chiave non corrisponde ad alcuna delle chiavi di dizionario, si otterrà un messaggio di errore.
Modificare un dizionario
L’operatore di indicizzazione consente anche di:
- modificare il valore associato a una chiave esistente
- aggiungere una nuova coppia chiave:valore se chiave non è presente nel dizionario Sintassi: dizionario[chiave] = valore
Semantica: se chiave fa parte di dizionario, il valore precedente viene sostituito da valore; altrimenti viene aggiunto al dizionario il nuovo elemento chiave:valore
items()
Per accedere alle chiavi e ai corrispondenti valori è possibile usare il metodo items()
Liste vs dizionari
Si consideri ora il caso in cui si debba memorizzare una sequenza o una collezione (non ordinata) di valori, la cui dimensione non sia nota al programmatore nel momento in cui scrive il programma.
Per esempio, questo può accadere in un programma che debba elaborare i dati relativi a:
- un insieme di studenti che abbiano sostenuto un esame
- un insieme di atleti che abbiano partecipato a una gara In questo caso è preferibile usare una lista, anche se tra i valori che si devono elaborare non esiste alcun ordinamento predefinito.
L’uso di un dizionario richiederebbe infatti al programmatore la scelta di una chiave distinta per ciascun valore da memorizzare al suo interno.
Insiemi
Omettendo i valori delle chiavi in un dizionario si ottiene un insieme, i cui elementi possono solo essere oggetti immutabili.
Esempio
I = {0,2,4,6,8}
- Possiamo verificare con in e not in se un oggetto appartenga o meno a un insieme e anche scandirne gli elementi con un ciclo for
- Non possiamo associare a una chiave alcun valore, cioè I[0] darà luogo a un errore. Si noti che un valore ripetuto in un insieme conta una sola volta e che l'ordine è indefinito:
{1,1,1} == {1} True
{1,2,3} == {2,1,3} True
Non è possibile accedere agli elementi di un set utilizzando l’indicizzazione poichè i set sono oggetti non ordinati e i suoi elementi non sono indicizzati.
Se I è un insieme possiamo:
- aggiungere ad esso un elemento
I.add(elemento)
- rimuovere un elemento
I.remove(elemento)
- creare nuovi insiemi che siano unione, intersezione e differenza di I con un altro insieme J
I.union(J)
I.intersection(J)
I.difference(J)
Dizionari e insiemi
Sia su dizionari che su insiemi è definita la funzione len che restituisce il numero di elementi del dominio del dizionario o dell'insieme:
len({1,2,3,4}) 4
len({1:2,3:4}) 2
Il dominio di un dizionario è un insieme che si può costruire a partire dal dizionario con l'operatore set
set({1:2,3:4,5:6}) {1,3,5
L'insieme vuoto si denota set()
Il dizionario vuoto si denota con {}
Si può convertire un insieme in una lista con list()
list({1,2,3,4}) [1,2,3,4]
File
Dal punto di vista di un programma Python un file consiste in una sequenza ordinata di valori. Più precisamente, un file può essere:
- una sequenza di byte, codificati come numeri interi con valori ∈ [0,255]
- una sequenza di caratteri (file di testo)
File di testo
Per i file di testo avremo due tipi di operazioni principali:
- lettura = acquisizione di una sequenza di caratteri del file, sottoforma di una stringa
- scrittura = memorizzazione nel file di una sequenza di caratteri contenuti in una stringa
Accesso al file
La lettura o la scrittura di dati su un file avvengono in tre fasi:
1. apertura del file, per mezzo della funzione built-in open
2. esecuzione di una o più operazioni di lettura o scrittura, per mezzo delle opportune funzioni built-in
3. chiusura del file, per mezzo della funzione built-in close
open
La funzione open restituisce un valore strutturato contenente alcune informazioni sul file. Sintassi: variabile = open(nome_file, modalita)
- variabile: il nome della variabile che verrà associata al file
- nome_file: una stringa contenente il nome del file
- modalità: una stringa che indica la modalità di apertura (lettura o scrittura)
Il nome del file che si desidera aprire deve essere passato come argomento della funzione open sotto forma di stringa. Il nome del file può essere:
- assoluto = cioè preceduto dalla sequenza (detta anche path) dei nomi delle directory che lo contengono a partire dalla directory radice del file system, scritta secondo la sintassi prevista dal sistema operativo del proprio calcolatore
- relativo = cioè composto dal solo nome del file: questo è possibile solo se la funzione open è chiamata da un programma o da una funzione che si trovi nella stessa directory che contiene il file da aprire
Nel caso di un file di nome dati.txt che si trovi nella directory C:\Users\Erika\ di un sistema operativo Windows:
- il nome relativo è dati.txt
- il nome assoluto è C:\Users\Erika\dati.txt
Se un file con lo stesso nome (dati.txt) è memorizzato nella directory /users/Erika/ di un sistema operativo Linux oppure Mac OS:
- il nome relativo è ancora dati.txt
- il nome assoluto è /users/Erika/dati.txt
È possibile aprire in modalità di lettura solo un file esistente. Se il file non esiste si otterrà un errore. La modalità di scrittura consente invece anche la creazione di un nuovo file. Più precisamente, attraverso la modalità di scrittura è possibile:
- creare un nuovo file
- aggiungere dati in coda a un file già esistente
- sovrascrivere (cancellare e sostituire) il contenuto di un file già esistente
Nella chiamata di open la modalità di accesso è indicata (come secondo argomento) da una stringa composta da un singolo carattere:
- "r" (read ): lettura (se il file non esiste si ottiene un errore)
- "w" (write): (sovra) scrittura
se il file non esiste viene creato
se il file esiste viene sovrascritto, cancellando i dati contenuti in esso
- "a" (append ): scrittura (aggiunta)
se il file non esiste viene creato
se il file esiste i nuovi dati saranno aggiunti in coda a quelli già esistenti
close
Quando le operazioni di lettura o scrittura su un file sono terminate, il file deve essere chiuso attraverso la funzione built-in close. Questo impedirà l’esecuzione di ulteriori operazioni su tale file, fino a che esso non venga eventualmente riaperto.
Sintassi: variabile.close()
dove variabile deve essere la variabile usata nell'apertura dello stesso file attraverso la funzione open
Esempio
write
In un file di testo che sia stato aperto in scrittura (in modalità "w" oppure "a") è possibile scrivere dati sotto forma di stringhe (cioè sequenze di caratteri) attraverso la funzione built-in write
Sintassi: variabile.write(stringa)
- variabile = è la variabile associata al file
- stringa = è una stringa contenente la sequenza di caratteri da scrivere nel file
La chiamata di write con un file aperto in lettura (in modalità "r") produce un messaggio di errore.
Lettura da file
Le operazioni di lettura da file possono essere eseguite attraverso tre diverse funzioni built-in:
- read
- readline
- readlines
Queste tre funzioni restituiscono una parte o l’intero contenuto del file sottoforma di una stringa oppure di una lista di stringhe. Il valore restituito dalle funzioni di lettura viene di norma memorizzato in una variabile per poter essere successivamente elaborato
read
La funzione read acquisisce l'intero contenuto di un file, che viene restituito sotto forma di una stringa. Le eventuali interruzioni di riga presenti nel file vengono codificate con il carattere newline "\n".
Sintassi: variabile.read()
dove variabile è la variabile associata al file.
readline
La funzione readline acquisisce una singola riga di un file, restituendola sotto forma di una stringa. Per “riga” di un file si intende una sequenza di caratteri fino alla prima interruzione di riga, oppure, se il file non contiene interruzioni di riga, l’intera sequenza di caratteri contenuta in esso. Nel primo caso anche l’interruzione di riga, codificata con il carattere newline, farà parte della stringa restituita da readline.
Sintassi: variabile.readline()
dove variabile indica come al solito la variabile associata al file.
readlines
La funzione readlines acquisisce l'intera sequenza di caratteri contenuta in un file, suddivisa per righe, e la restituisce sotto forma una lista di stringhe, ciascuna delle quali contiene una riga del file (incluso il carattere newline).
Sintassi: variabile.readlines()
dove variabile è la variabile associata al file.
La funzione readlines è utile quando si desidera elaborare separatamente ogni riga di un dato file.
A differenza di read consente l'acquisizione dell'intero file con una sola chiamata.
Eccezioni
Alcune possibili eccezioni per i programmi in Python sono:
- la divisione di un valore per zero
- la richiesta di un elemento di una lista con un indice errato
- la richiesta di una chiave non esistente in un dizionario
with
L’istruzione with è una struttura di controllo del flusso di esecuzione
Sintassi: with espressione [as variabile]:
blocco_di_istruzioni
dove espressione è una espressione che deve produrre un oggetto che supporta il context management protocol cioè un oggetto che abbia i metodi __enter__() e __exit__()
Il valore di ritorno di __enter__() viene assegnato a variabile (se fornita).
L’istruzione with garantisce che se il metodo __enter__() termina senza errori allora la funzione __exit__() sarà sempre invocata.
Dopo l’esecuzione del with l’oggetto file f verrà automaticamente chiuso, anche se dovesse verificarsi una eccezione nel ciclo for
Commenti
Posta un commento