vuoi
o PayPal
tutte le volte che vuoi
Esempio: Se voglio creare una lista di tuple con le coppie in cui
x è diverso da y, con x che varia tra 1 e 3, mentre y
varia tra 3,1 e 4, posso utilizzare la seguente sintassi:
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x !=
y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
Le list comprehension permettono di creare facilmente anche nuove liste basate su
liste già esistenti.
Esempio:
Ad esempio, se voglio creare una lista con i valori di una seconda lista raddoppiati
scriverò: >>> vec = [-4, -2, 0, 2, 4]
>>> [x*2 for x in vec] # create a new list with the values doubled
Attenzione alle parentesi tonde quando si utilizzano le tuple (es. [x, x**2 for x in (x,
range(6)] fornisce errore, perché la tupla deve essere racchiusa tra parentesi, cioè [
x**2) for x in range(6)]).
Possono capitare casi in cui debba cancellare dati che occupano della memoria.
Un metodo prevede l’assegnamento del valore “None” al riferimento, in questo modo
l’oggetto referenziato precedentemente verrà rimosso dalla memoria dal garbage
collector.
In alternativa, posso cancellare esplicitamente un oggetto, utilizzo lo statement “del”.
Oltre a cancellare l’oggetto in memoria, esso rimuove anche i riferimenti ad esso.
Ciò significa che a meno che non inizializzi la variabile che riferiva l’oggetto eliminato,
non potrò più usarla.
Mediante tale statement posso utilizzare anche le operazioni di slicing, ad esempio:
>>> a = [-1, 1, 66.25, 333, 333, 1234.5], >>> del a[0], [1, 66.25, 333, 333,
1234.5] (elimina il primo valore)
Posso azzerare completamente la lista mediante “del a[:]” e il riferimento punterà ad
una lista vuota.
del a
Se utilizzo “ ”, invece, vado a cancellare l’intera lista ed il riferimento (se voglio
utilizzare nuovamente la variabile dovrò inizializzarla, altrimenti non potrò accedervi in
seguito alla cancellazione).
Python non definisce l’array come tipo predefinito.
In python gli array sono mutabili e sono visti come contenitori OMOGENEI di elementi.
Tranne questa differenza, dal punto di vista operazionale non ci sono grosse differenze
(mancano alcuni metodi rispetto alle stringhe).
Dal momento che non è un tipo predefinito, per utilizzare un array devo importare una
libreria specifica che contiene la sua definizione.
La prima è definita all’interno della libreria array, quella più semplice e meno
utilizzata, mentre l’altra definizione è contenuta nella libreria numpy (utilizzo la
from numpy import array
sintassi , in realtà sto importando solo la sottoparte
“array” dalla libreria numpy -> importazione puntuale).
Successivamente, posso utilizzare un array mediante il suo costruttore:
arr = array('I',range(3))
Se utilizzo la libreria “array”, la sintassi è arr = array(range(3))
Se utilizzo la libreria “array”, la sintassi è
Si nota che nel primo caso, il costruttore della libreria “array” prevede anche la
tipologia di dato che conterrà l’array (“I” indica che sarà un array di elementi interi
senza segno).
Nel caso in numpy, invece, posso metterci qualsiasi elemento ed il tipo verrà inferito
automaticamente.
Ad esempio, un intero contenuto in un array di numpy viene trasformato in maniera
automatica in un intero di python quando viene prelevato/acceduto.
Un altro vantaggio nell’utilizzo di numpy è la presenza di numerose operazioni già
implementate.
Ad esempio, se volessi sommare a tutti gli elementi il valore 10, basterebbe utilizzare
l’operatore +, perché viene trasformato internamente in un ciclo (darebbe errore nel
caso in cui utilizzassi la libreria array, perché non esiste tale operazione).
Python propone come dato predefinito anche il tipo “insieme”, la cui parola chiave è
sets.
La differenza sostanziale rispetto ad una lista, è che gli insiemi non ammettono
duplicati.
Se ho già degli elementi da mettere all’interno dell’insieme, utilizzo la notazione con le
graffe.
Se l’insieme è vuoto, non posso utilizzare le parentesi graffe, perché verrebbe creato
un dizionario.
Per risolvere tale problema, devo utilizzare esplicitamente il suo costruttore.
Esempio: rimozione automatica dei duplicati
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket) # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
Si nota che gli insiemi non sono ordinati, per cui ogni volta che andrò a modificarlo è
possibile che l’ordine degli elementi cambi.
Nel momento in cui vado ad inserire un
elemento in un insieme, viene effettuato un
controllo sullo specifico valore referenziato dagli
elementi dell’insieme e non dal semplice
riferimento.
Se tale valore è già presente, allora non verrà
inserito nell’insieme.
Con la parola chiave “in” posso effettuare un
controllo d’inclusione, come nel caso delle
stringhe.
Posso effettuare diverse operazioni “proprie”
degli insiemi, ossia quelle riportate a lato.
A volta risulta utile accedere ai dati non attraverso un indice, ma attraverso
un’informazione.
Per fare ciò si possono utilizzare i dizionari, il quale è costituito da coppie {chiave :
valore}.
I dizionari vengono introdotti dal tipo dict e poiché posseggono un tipo, posso
assegnargli alle variabili.
Posso accedere al dizionario tramite le parentesi quadre, cioè dictionary_name[key].
Analogamente, posso effettuare un assegnamento nel dizionario tramite
dictionary_name[key] = value (nel caso in cui la chiave non esista, verrà creata in
automatico una nuova entry con la coppia key : value).
Si sottolinea che i dizionari sono non ordinati e non possono essere “None”.
Inoltre, le parole chiave devono essere immutabili (non posso utilizzare un array come
chiave), nonché UNICHE, mentre i valori possono anche non essere immutabili.
I dizionari offrono diversi metodi con cui lavorare, ad esempio:
len(dict_name)
+ e * non sono definiti per i dizionari
dict.keys() restituisce le chiavi in qualche ordine
dict.values() restituisce i valori in qualche ordine
dict.keys() restituisce le coppie (chiave, valori) in
qualche ordine
key in dict restituisce “true” se il dizionario
contiene la chiave
Per ciclare su un dizionario (ordine sparso) posso utilizzare
un ciclo for sugli elementi forniti dal metodo dict.keys() (solo nel caso del ciclo sulle
chiavi tramite ciclo for posso omettere il metodo).
Inoltre, vengono predisposti anche i seguenti metodi:
dict.get(key), analogo all’accesso tramite parentesi quadre per ottenere un
valore ma non restituisce un errore nel caso in cui il dizionario con contenga
quella specifica chiave
dict.clear() per azzerare il dizionario
dict.copy() (attenzione agli oggetti mutabili all’interno del dizionario)
Per ciò che è stato detto precedentemente, l’iterazione sul dizionario sarà non
ordinata.
Nel caso in cui volessimo iterare in maniera ordinata, posso utilizzare il metodo .sort().
Mediante la parola chiave “in” posso ciclare sulle chiavi, non sui valori (se volessi farlo,
dovrei trasformare il dizionario in una lista e successivamente ciclare sui valori).
Librerie e moduli in python
Si ricorda che python vede tutto come un oggetto.
Ad esempio, nel caso di una funzione, Quello che python fa è compilare il codice della
funzione, metterlo in memoria, mentre il nome della funzione diventa una variabile
che referenzia una parte di memoria in cui ho il codice (Ciò funziona anche per i
moduli stessi, per la definizione delle classi, così come per le istanze delle classi,
variabili, ecc…).
In python una libreria è chiamata modulo e può contenere una serie di definizioni
(classi, funzioni, variabili).
Quando vado ad importare un certo modulo, posso accedere a tutto quello che è
definito al suo interno tramite la notazione puntata
Una volta importato un modulo, posso accedere a tutto quello che è presente in tale
modulo mediante la notazione puntata (es. se voglio accedere a pluto nel modulo
pippo, dovrò scrivere pippo.pluto).
Dal momento che tutto è pubblico e visibile, ciò comporta che potrei anche cambiare il
valore di una variabile importante di un modulo, ad esempio la costante del pigreco.
convenzioni
In python, funziona per , ad esempio il doppio underscore indica le
variabili private.
In python non esiste un reale “main”, ma lo simula.
Tuttavia, risulta utile definire un main come “punto d’accesso” per l’esecuzione del
codice.
In realtà, quando vado a caricare un file python, l’interprete del linguaggio prende tale
file e, indipendentemente dal nome del file e dalla sua definizione (modulo o meno), lo
chiama internamente “main” (il riferimento nel momento in cui verrà referenziato il
codice del file sarà “__main__”).
Invece, nel caso di import successivi all’interno del file principale, i moduli verranno
chiamati con il loro nome (es. import pippo produrrà un riferimento con lo stesso
nome, cioè pippo).
A questo punto, se io dentro il file pongo “if __name__ == “__main__””, allora gli
statment all’interno dell’if verranno eseguiti solo se quel modulo è quello che ho
fornito al compilatore inizialmente.
Esempio:
Considero il file m.py, al cui interno è definito l’import di un secondo file s.py.
Entrambi i file contengono l’if precedente con alcune istruzioni.
Se passo come file principale il file “m.py” al compilatore, cioè “python m.py”, allora le
istruzioni eseguite saranno solo quelle del file m.py e non di s.py, perché internamente
è stato rinominato “__main__”.
Se il file “s.py” non avesse il controllo relativo al nome, ma solo le istruzioni all’interno
dell’if, nel momento in cui viene importato il file da parte di “m.py” tali istruzioni
verrebbero eseguite.
Posso effettuare anche un import selettivo mediante “from module_name import
fn_name1, fn_name2”.
Ottengo diversi risultati:
occupo meno memoria, perché in memoria ho solo la definizione di “fn_name1”
e “fn_name2”
so per certo quello che ho importato e quindi ho so