Articolo originale: The Python Handbook – Learn Python for Beginners

Il manuale Python segue la regola dell'80/20: impara l'80% dell'argomento nel 20% del tempo.

Trovo che questo approccio offra una panoramica completa.

Questo manuale non ha lo scopo di coprire tutto ciò che riguarda Python. Si focalizza sul fulcro del linguaggio, cercando di semplificare gli argomenti più complessi.

Spero che il contenuto di questo manuale ti aiuti a raggiungere il tuo obiettivo: imparare le basi di Python.

Nota: puoi ottenere le versioni PDF, ePub e Mobi di questo Manuale Python (versione originale inglese)

Buona lettura!

Indice

Introduzione a Python

Python sta letteralmente mangiando il mondo della programmazione. Sta avendo una crescita in popolarità e utilizzo senza precedenti nella storia dei computer.

Python eccelle in una vasta gamma di situazioni – shell scripting, automazione di attività e sviluppo web sono alcuni semplici esempi.

Python è la prima scelta per l'analisi di dati e il machine learning, ma si presta anche per la creazione di giochi e per lavorare con dispositivi integrati.

E soprattutto è il linguaggio scelto per i corsi introduttivi di informatica nelle università di tutto il mondo.

Tanti studenti imparano Python come primo linguaggio di programmazione. Molti lo stanno studiando proprio adesso e molti altri lo apprenderanno in futuro. E per buona parte di loro, Python sarà l'unico linguaggio di programmazione di cui hanno bisogno.

Grazie a questa condizione singolare, è probabile che Python diventi ancora più popolare in futuro.

Il linguaggio è semplice, espressivo e piuttosto diretto.

L'ecosistema è enorme, e sembra esserci una libreria per ogni cosa tu possa immaginare.

Python è un linguaggio di programmazione ad alto livello adatto per i principianti, grazie alla sua sintassi intuitiva, la sua comunità enorme e il suo ecosistema dinamico.

È anche apprezzato da professionisti in molti campi differenti.

Parlando tecnicamente, Python è un linguaggio interpretato che non ha una fase intermedia di compilazione come un linguaggio compilato, ad esempio C o Java.

E come molti linguaggi interpretati, è dinamicamente tipizzato. Ciò vuol dire che   non devi indicare il tipo di variabili che utilizzi, e che le variabili non sono vincolate da un tipo specifico.

Questo ha vantaggi e svantaggi. In particolare, permette di scrivere programmi più veloci, d'altro canto, rende meno utili gli strumenti per prevenire possibili bug. Ciò vuol dire che potrai riscontrare determinati problemi soltanto durante l'esecuzione del programma.

Python supporta un'ampia varietà di paradigmi di programmazione differenti, tra cui la programmazione procedurale, la programmazione orientata agli oggetti e la programmazione funzionale. È abbastanza flessibile da adattarsi a molte esigenze diverse.

A partire dal 1991, quando fu creato da Guido van Rossum, ha continuato a guadagnare popolarità – specialmente negli ultimi 5 anni, come mostra questa infografica di Google Trends:

Screen-Shot-2020-11-09-at-19.22.38

Iniziare con Python è molto semplice. Tutto ciò di cui hai bisogno è installare il pacchetto ufficiale da python.org, per Windows, macOS o Linux, e sei pronto per partire.

Se sei nuovo al mondo della programmazione, nelle prossime sezioni ti guiderò partendo da zero per arrivare a diventare un programmatore Python.

E anche se sei un programmatore specializzato in un altro linguaggio, vale la pena di conoscere Python perché è probabile che il suo utilizzo continui a crescere.

I linguaggi di livello più basso come C++ e Rust potrebbero essere perfetti per programmatori esperti, ma sono impegnativi per iniziare e richiedono molto tempo per essere padroneggiati.

Python, al contrario, è un linguaggio di programmazione per tutti – studenti, persone che lavorano quotidianamente con Excel, scienziati e altri.

È il primo linguaggio che chi è interessato alla programmazione dovrebbe imparare.

Come installare Python

Vai su https://www.python.org, vai sul menu Downloads, scegli il tuo sistema operativo e ti apparirà un riquadro con un link per il download del pacchetto ufficiale:

Screen-Shot-2020-11-09-at-13.57.36-1

Assicurati di seguire le istruzioni specifiche per il tuo sistema operativo. Per macOS puoi trovare una guida dettagliata su https://flaviocopes.com/python-installation-macos/.

Come eseguire programmi in Python

Ci sono diversi modi per eseguire dei programmi Python.

In particolare, c'è una differenza tra l'uso di prompt interattivi, in cui il codice Python viene eseguito immediatamente, e salvare un programma Python in un file da eseguire.

Iniziamo con i prompt interattivi.

Se apri il tuo terminale e scrivi python, vedrai una schermata come questa:

Screen-Shot-2020-11-10-at-13.44.07

Questo è il REPL (Read-Evaluate-Print-Loop) Python.

Nota il simbolo >>> e il cursore subito dopo. Puoi scrivere qualsiasi codice Python qui e premere il tasto Invio per eseguirlo.

Ad esempio, proviamo a definire una nuova variabile usando:

nome = "Flavio"

e stampiamo il suo valore cone print():

print(nome)
Screen-Shot-2020-11-10-at-14.11.57
Nota: nel REPL, puoi anche scrivere soltanto nome, premere il tasto Invio e otterrai il valore. Ma in un programma, non vedrai alcun output se fai ciò – hai bisogno di usare print().

Ogni riga di Python che scrivi qui verrà eseguita immediatamente.

Scrivi quit() per uscire dal REPL Python.

Puoi accedere allo stesso prompt interattivo usando l'applicazione IDLE installata automaticamente da Python:

Screen-Shot-2020-11-10-at-14.13.25

Potrebbe essere più conveniente da usare perché poi muoverti con il mouse e fare copia & incolla più facilmente che nel terminale.

Tutto ciò è integrato in Python di default. Tuttavia, consiglio di installare IPython, probabilmente la miglior applicazione riga di comando REPL che puoi trovare.

Installala con:

pip install ipython

Assicurati che i file binari di pip siano nel tuo percorso, poi esegui ipython:

Screen-Shot-2020-11-11-at-09.36.29

ipython è un'altra interfaccia che ti permette di lavorare con un REPL Python e offre delle funzionalità come colorazione della sintassi, completamento del codice e molto altro.

Il secondo modo per eseguire un programma Python è scrivere il codice del programma in un file, ad esempio program.py:

Screen-Shot-2020-11-10-at-14.01.24

e poi eseguirlo con python program.py:

Screen-Shot-2020-11-10-at-14.01.32
Nota che salviamo i programmi Python con l'estensione .py - è una convenzione.

In questo caso, il programma è eseguito interamente, non riga per riga. Questo è il modo tipico per eseguire dei programmi.

Usiamo il REPL per prototipazione rapida e per imparare.

Su Linux e macOS, un programma Python può essere anche trasformato in uno script di shell, anteponendo a tutto il suo contenuto una riga speciale che indica quale versione di Python usare per eseguirlo.

Sul mio sistema l'eseguibile di Python si trova in /usr/bin/python3, quindi scrivo #!/usr/bin/python3 nella prima riga:

Screen-Shot-2020-11-10-at-14.17.26

Poi posso impostare i permessi di esecuzione del file:

chmod u+x program.py

ed eseguire il programma con:

./program.py
Screen-Shot-2020-11-10-at-14.18.42

Questo è particolarmente utile quando scrivi degli script che interagiscono con il terminale.

Abbiamo molti altri modi di eseguire dei programmi Python.

Uno di questi è usare VS Code e, in particolare, l'estensione ufficiale Python per Microsoft:

Screen-Shot-2020-11-10-at-14.23.32

Dopo aver installato questa estensione, avrai funzionalità come completamento automatico del codice e controllo di errori, formattazione automatica e pulizia del codice con pylint e alcuni comandi speciali, tra cui:

Python: Start REPL per eseguire il REPL nel terminale integrato:

Screen-Shot-2020-11-10-at-14.31.36

Python: Run Python File in Terminal per eseguire il file corrente nel terminale:

Screen-Shot-2020-11-10-at-14.31.06

Python: Run Current File in Python Interactive Window:

Screen-Shot-2020-11-10-at-14.30.02-1

e molti altri. Apri la command palette (View -> Command Palette, o Cmd-Shift-P) e digita python per vedere tutti i comandi relativi a Python:

Screen-Shot-2020-11-10-at-14.30.02

Un altro modo semplice per eseguire del codice Python è usare repl.it, un sito web molto utile che fornisce un ambiente di programmazione in cui puoi creare ed eseguire app in qualsiasi linguaggio, incluso Python:

Screen-Shot-2020-11-10-at-14.33.58

Iscriviti (è gratuito), poi in "create a repl" clicca su Python:

Screen-Shot-2020-11-10-at-14.46.34

Visualizzerai immediatamente un editor con un file main.py, pronto per essere riempito con un bel po' di codice Python:

Screen-Shot-2020-11-10-at-14.47.15

Una volta che hai del codice, clicca su "Run" per eseguirlo sul lato destro della finestra:

Screen-Shot-2020-11-10-at-14.48.09

Credo che repl.it sia comodo perché:

  • puoi condividere facilmente del codice con un link
  • più persone possono lavorare sullo stesso codice
  • supporta programmi a lunga esecuzione
  • puoi installare pacchetti
  • fornisce un database chiave-valore per applicazioni più complesse

Python 2 vs Python 3

Uno degli argomenti chiave che dovremmo affrontare dall'inizio è la questione Python 2 vs Python 3.

Python 3 è stato introdotto nel 2008 ed è stato in sviluppo come la versione principale di Python, mentre Python 2 ha continuato ad essere manutenuto con aggiustamenti di bug e patch di sicurezza fino all'inizio del 2020.

Da quel momento, il supporto per Python 2 è stato discontinuo.

Molti programmi sono ancora scritti usando Python 2 e alcune aziende lavorano ancora attivamente con questi programmi, infatti il passaggio a Python 3 non è banale e richiede molto lavoro di aggiornamento. Inoltre, i passaggi importanti e di una certa portata introducono sempre dei nuovi bug.

Comunque, il codice nuovo, a meno che tu ti debba attenere alle regole della tua azienda che impongono di usare Python 2, dovrebbe essere sempre scritto in Python 3.

Questo manuale è focalizzato su Python 3.

Fondamenti di Python

Variabili in Python

In Python, possiamo creare una nuova variabile assegnando un valore a un'etichetta, usando l'operatore di assegnazione (=).

In questo esempio, assegniamo una stringa con il valore "Roger" all'etichetta nome:

nome = "Roger"

Ecco un altro esempio con un numero:

età = 8

Il nome di una variabile può essere composto da lettere, numeri e dal trattino basso (_), ma non può iniziare con un numero. Questi sono tutti dei nomi validi per una variabile:

nome1
ANNO
aNNO
a11111
mio_nome
_nome

Questi sono dei nomi non validi per una variabile:

123
test!
nome%

Per il resto, tutto può essere valido a meno che si tratti di una parola chiave, come for, if, while, import e altre.

Non c'è bisogno di memorizzarle, dato che Python ti avvisa se ne utilizzi una come variabile, e imparerai a riconoscerle gradualmente come parte della sintassi del linguaggio di programmazione Python.

Espressioni e istruzioni in Python

Un'espressione è qualsiasi codice che restituisce un valore. Ad esempio:

1 + 1
"Roger"

Un'istruzione, invece, è un'operazione su un valore. Per esempio, queste sono due istruzioni:

nome = "Roger"
print(nome)

Un programma è formato da una serie di istruzioni. Ogni istruzione occupa una riga, ma puoi utilizzare un punto e virgola per avere più di un'istruzione su una sola riga:

nome = "Roger"; print(nome)

Commenti

In un programma Python, tutto ciò che si trova dopo un cancelletto è ignorato e considerato un commento:

#Questo è un commento

nome = "Roger" # questo è un commento inline

Indentazione in Python

L'indentazione in Python è importante.

Non puoi indentare il codice casualmente, in questo modo:

nome = "Flavio"
    print(nome)

In alcuni altri linguaggi lo spazio bianco non è rilevante, ma in Python l'indentazione conta.

In questo caso, se provi a eseguire questo programma otterrai l'errore IndentationError: unexpected indent, perché l'indentazione ha un significato particolare.

Tutto ciò che è indentato appartiene a un blocco, come un'istruzione di controllo, un blocco condizionale o il corpo di una funzione o di una classe. Vedremo più dettagli a questo riguardo in seguito.

Tipi di dati in Python

Python ha diversi tipi di dati integrati.

Se crei la variabile nome assegnandole il valore "Roger", questa variabile rappresenta automaticamente un tipo di dato stringa.

nome = "Roger"

Puoi verificare il tipo di una variabile usando la funzione type(), passando la variabile come argomento e poi confrontando il risultato con str:

nome = "Roger"
type(nome) == str #True

O usando isinstance():

nome = "Roger"
isinstance(nome, str) #True
Osserva che per vedere il valore True in Python, fuori dal REPL, hai bisogno di inserire il codice in print(), ma evito di usarlo per chiarezza.

Qui abbiamo usato la classe str, ma funziona allo stesso modo per altri tipi di dati.

Ad esempio, i numeri. I numeri interi sono rappresentati usando la classe int. I numeri in virgola mobile (frazioni) sono invece di tipo float:

età = 1
type(età) == int #True
frazione = 0.1
type(frazione) == float #True

Hai visto come creare un tipo da un valore letterale come:

nome = "Flavio"
età = 20

Python rileva automaticamente il tipo di dato a seconda del tipo di valore.

Puoi anche creare una variabile di un tipo specifico usando il costruttore di classe, passando un valore letterale o il nome di una variabile:

nome = str("Flavio")
altro_nome = str(nome)

Puoi anche passare da un tipo a un altro usando il costruttore di classe. Python proverà a determinare il valore corretto, ad esempio, estraendo un numero da una stringa:

età = int("20")
print(età) #20

frazione = 0.1
int_frazione = int(frazione)
print(int_frazione) #0

Questa operazione è detta conversione di tipo. Ovviamente, potrebbe non funzionare a seconda del valore passato. Se scrivi test invece di 20 nella stringa qui sopra, otterrai l'errore: ValueError: invalid literal for int() with base 10: 'test'.

Questi sono sono i tipi di base, ma ci sono molti altri tipi in Python:

  • complex per i numeri complessi
  • bool per  i booleani
  • list per le liste
  • tuple per le tuple
  • range per gli intervalli
  • dict per i dizionari
  • set per i set

e ancora altri!

Li esploreremo presto tutti.

Operatori in Python

Gli operatori Python sono simboli che usiamo per eseguire operazioni su valori e variabili.

Possiamo dividere gli operatori in base al tipo di operazione che svolgono:

  • operatore di assegnazione
  • operatori aritmetici
  • operatori di confronto
  • operatori logici
  • operatori bitwise

e in aggiunta qualche altro operatore interessante come is e in.

Operatore di assegnazione in Python

L'operatore di assegnazione è usato per assegnare un valore a una variabile:

età = 8

O per riassegnare il valore di una variabile a un'altra variabile:

età = 8
altra_variabile = età

A partire da Python 3.8, l'operatore tricheco (:=) è utilizzato per assegnare un valore a una variabile come parte di un'altra operazione. Ad esempio, all'interno di un if o di una parte condizionale di un loop.

Operatori aritmetici in Python

Python possiede svariati operatori aritmetici: +, -, *, / (divisione), % (modulo), ** (elevamento a potenza) e // (divisione intera):

1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2
Nota che non è necessario aggiungere spazi tra gli operandi, ma rende il codice più leggibile.

- funziona anche come operatore unario meno:

print(-4) #-4

+ è anche usato per concatenare stringhe:

"Roger" + " è un bravo cane"
#Roger è un bravo cane

Possiamo combinare l'operatore di assegnazione con gli operatori aritmetici:

  • +=
  • -=
  • *=
  • /=
  • %=
  • ..e così via

Esempio:

età = 8
età += 1
# età adesso ha valore 9

Operatori di confronto in Python

Python possiede diversi operatori di confronto:

  • ==
  • !=
  • >
  • <
  • >=
  • <=

Puoi utilizzare questi operatori per ottenere un valore booleano (True o False) a seconda del risultato:

a = 1
b = 2

a == b #False
a != b #True
a > b #False
a <= b #True

Operatori booleani in Python

Python ha i seguenti operatori booleani:

  • not
  • and
  • or

Lavorando con gli attributi True e False, gli operatori booleani lavorano come AND, OR e NOT logici, e sono spesso usati nella valutazione di espressioni condizionali if:

condizione1 = True
condizione2 = False

not condizione1 #False
condizione1 and condizione2 #False
condizione1 or condizione2 #True

Altrimenti, attenzione a un possibile motivo di confusione:

or usato in un'espressione restituisce il valore del primo operando che non è un valore falsy (False, 0, '', []..). Altrimenti restituisce il secondo operando.

print(0 or 1) ## 1
print(False or 'hey') ## 'hey'
print('hi' or 'hey') ## 'hi'
print([] or False) ## 'False'
print(False or []) ## '[]'

La documentazione di Python ne descrive il comportamento come: "se x è False, restituisce y, altrimenti x".

and valuta solo il secondo argomento se il primo è True. Quindi se il primo argomento è falsy (False, 0, '', []..), lo restituisce. Altrimenti valuta il secondo argomento:

print(0 and 1) ## 0
print(1 and 0) ## 0
print(False and 'hey') ## False
print('hi' and 'hey') ## 'hey'
print([] and False ) ## []
print(False and [] ) ## False

La documentazione di Python ne descrive il comportamento come:  "se x è False, restituisce x, altrimenti y".

Operatori bitwise in Python

Alcuni operatori sono utilizzati per lavorare su bit e numeri binari:

  • & esegue un'operazione AND binaria
  • | esegue un'operazione OR binaria
  • ^ esegue un'operazione XOR binaria
  • ~ esegue un'operazione NOT binaria
  • << operazione di spostamento a sinistra
  • >> operazione di spostamento a destra

Le operazioni bitwise (o bit a bit) sono usate raramente, soltanto in situazioni specifiche, ma vale la pena menzionarle.

is e in in Python

is è detto operatore di identità. Viene usato per confrontare due oggetti e restituire True se sono entrambi lo stesso oggetto. Parleremo degli oggetti più avanti.

in è detto operatore di appartenenza. È usato per dire se un valore è contenuto in una lista o in una sequenza. Parleremo di liste e sequenze più avanti.

Operatore ternario in Python

L'operatore ternario in Python ti permette di definire velocemente un condizionale.

Ipotizziamo di avere una funzione che confronta una variabile età con il valore 18 e restituisce vero o falso in base al risultato.

Invece di scrivere:

def adulto(età):
    if età > 18:
        return True
    else:
        return False

Puoi implementarla con un operatore ternario, in questo modo:

def adulto(età):
    return True if età > 18 else False

Prima definisci il risultato se la condizione è vera, poi valuti la condizione e in seguito definisci il risultato se la condizione è falsa:

<risultato_se_true> if <condizione> else <risultato_se_false>

Stringhe in Python

Una stringa in Python è una serie di caratteri racchiusi tra virgolette singole o doppie:

"Roger"
'Roger'

Puoi assegnare una stringa a una variabile:

nome = "Roger"

Puoi concatenare due stringhe usando l'operatore +:

frase = "Roger" + " è un bravo cane"

E puoi aggiungere una stringa alla fine di un'altra stringa con +=:

nome = "Roger"
nome += " è un bravo cane"

print(nome) #Roger è un bravo cane

Puoi convertire un numero in una stringa usando il costruttore di classe str:

str(8) #"8"

Questo è essenziale per concatenare un numero a una stringa:

print("Roger ha " + str(8) + " anni") #Roger ha 8 anni

Una stringa può essere multi-riga se definita con una sintassi speciale, cioè quando è racchiusa tra virgolette triple:

print("""Roger ha

    8

anni
""")

#virgolette singole o doppie

print('''
Roger ha

    8

anni
''')

Una stringa possiede un insieme di metodi integrati, come:

  • isalpha() per verificare se una stringa contiene solo lettere e non è vuota
  • isalnum() per verificare se una stringa contiene solo lettere e cifre e non è vuota
  • isdecimal() per verificare se una stringa contiene solo cifre e non è vuota
  • lower() per ottenere una versione minuscola della stringa
  • islower() per verificare se una stringa è minuscola
  • upper() per ottenere una versione maiuscola della stringa
  • isupper() per verificare se una stringa è maiuscola
  • title() per ottenere una stringa in cui tutti i primi caratteri sono maiuscoli
  • startsswith() per verificare se una stringa inizia con una specifica sotto-stringa
  • endswith() per verificare se una stringa termina con una specifica sotto-stringa
  • replace() per sostituire parte di una stringa
  • split() per dividere una stringa in corrispondenza di uno specifico carattere
  • strip() per eliminare gli spazi da una stringa
  • join() per aggiungere lettere alla fine di una stringa
  • find() per trovare la posizione di una sottostringa

e molti altri.

Nessuno di questi metodi altera la stringa originale. Invece, restituiscono una nuova stringa modificata. Ad esempio:

nome = "Roger"
print(nome.lower()) #"roger"
print(nome) #"Roger"

Puoi anche usare delle funzioni globali per lavorare con le stringhe.

In particolare, penso a len(), che ti dà la lunghezza di una stringa:

nome = "Roger"
print(len(nome)) #5

L'operatore in ti permette di controllare se una stringa contiene una sotto-stringa:

nome = "Roger"
print("ger" in nome) #True

L'escaping è un modo per aggiungere caratteri speciali all'interno di una stringa.

Ad esempio, come puoi aggiungere delle virgolette doppie in una stringa che è circondata da virgolette doppie?

nome = "Roger"

"Ro"Ger" non funzionerà, perché Python penserà che la stringa sia "Ro".

Occorre usare un carattere di escape, la barra rovesciata \, all'interno della stringa:

nome = "Ro\"ger"

Questo vale anche per le virgolette singole \' e per caratteri speciali di formattazione come \t per tab, \n per una nuova riga e \\ per la barra rovesciata.

Data una stringa, puoi ottenere i suoi caratteri usando le parentesi quadre per raggiungere un carattere specifico con il suo indice, partendo da 0:

nome = "Roger"
nome[0] #'R'
nome[1] #'o'
nome[2] #'g'

Usando un numero negativo, il conto parte dalla fine:

nome = "Roger"
nome[-1] #"r"

Puoi anche usare un intervallo, in quello che è chiamato slicing:

nome = "Roger"
nome[0:2] #"Ro"
nome[:2] #"Ro"
nome[2:] #"ger"

Booleani in Python

Python dispone del tipo bool, che ha due valori: True e False (con la prima lettera maiuscola).

done = False
done = True

I booleani sono particolarmente utili con strutture di controllo condizionali come le istruzioni if:

variabile = True

if variabile:
    # esegui questo codice
else:
    # esegui altro codice

Valutando se un valore è True o False, se il valore non è un bool, esistono delle regole a seconda del tipo di dato:

  • i numeri sono sempre True eccetto lo 0
  • le stringhe sono False solo se vuote
  • liste, tuple, set e dizionari sono False solo se vuoti

Puoi controllare se un valore è booleano in questo modo:

variabile = True
type(variabile) == bool #True

O usando isinstance(), passando 2 argomenti, la variabile e la classe bool:

variabile = True
isinstance(variabile, bool) #True

Anche la funzione globale any() è molto utile per lavorare con i booleani, e restituisce True se uno dei valori dell'iterabile (una lista, ad esempio) passato come argomento è True:

libro_1_letto = True
libro_2_letto = False

letto_qualche_libro = any([libro_1_letto, libro_2_letto])

La funzione globale all() funziona allo stesso modo, ma restituisce True se tutti i valori passati sono True:

ingredienti_comprati = True
pasto_preparato = False

pronto_per_servire = all([ingredienti_comprati, pasto_preparato])

Numeri in Python

I numeri in Python possono essere di tre tipi: int, float e complex.

Numeri interi in Python

I numeri interi sono rappresentati usando la classe int. Puoi definire un intero usando un valore letterale:

età = 8

Puoi anche definire un numero intero usando il costruttore int():

età = int(8)

Per verificare che una variabile sia di tipo int, puoi usare la funzione globale type():

type(età) == int #True

Numeri in virgola mobile in Python

I numeri in virgola mobile (frazioni) sono di tipo float. Puoi definire un float usando un valore letterale:

frazione = 0.1

Oppure il costruttore float():

frazione = float(0.1)

Per verificare se una variabile è di tipo float, puoi usare la funzione globale type():

type(frazione) == float #True

Numeri complessi in Python

I numeri complessi in Python sono di tipo complex.

Puoi definirli con un valore letterale:

numero_complesso = 2+3j

o con il costruttore complex():

numero_complesso = complex(2, 3)

Una volta che hai un numero complesso, puoi ottenere la sua parte reale e la sua parte immaginaria:

numero_complesso.real #2.0
numero_complesso.imag #3.0

Ancora, per verificare che una variabile sia di tipo complex, puoi usare la funzione globale type():

type(numero_complesso) == complex #True

Operazioni aritmetiche sui numeri in Python

Puoi svolgere operazioni aritmetiche sui numeri usando gli operatori aritmetici: +, -, *, / (divisione), % (modulo), ** (elevamento a potenza) e // (divisione intera):

1 + 1 #2
2 - 1 #1
2 * 2 #4
4 / 2 #2
4 % 3 #1
4 ** 2 #16
4 // 2 #2

e puoi usare gli operatori di assegnazione composti:

  • +=
  • -=
  • *=
  • /=
  • %=

..e così via

Per svolgere operazioni rapide sulle variabili:

età = 8
età += 1

Funzioni integrate in Python

Ci sono due funzioni integrate utili con i numeri:

abs() restituisce il valore assoluto di un numero.

Dato un numero, round() restituisce il suo valore approssimato all'intero più vicino:

round(0.12) #0

Puoi specificare un secondo parametro per impostare la precisione decimale:

round(0.12, 1) #0.1

Svariate altre funzioni di utilità e costanti sono fornite dalla libreria standard di Python:

  • il pacchetto math offre funzioni matematiche e costanti
  • il pacchetto cmath offre utilità per lavorare con i numeri complessi
  • il pacchetto decimal contiene utilità per lavorare con decimali e float
  • il pacchetto fractions fornisce utilità per lavorare con i numeri razionali

Ne esploreremo qualcuno più avanti.

Costanti in Python

Python non ha un modo per imporre che un valore rimanga costante.

La cosa che ci si avvicina di più è l'uso di un enum:

class Costanti(Enum):
    LARGHEZZA = 1024
    ALTEZZA = 256

Per raggiungere ogni valore usiamo, ad esempio, Costanti.LARGHEZZA.value.

Nessuno può riassegnare quel valore.

Altrimenti, se vuoi fare affidamento alle convenzioni di nomenclatura, puoi dichiarare in maiuscolo le variabili il cui valore non deve variare mai:

LARGHEZZA = 1024

Nessuno può impedirti di sovrascrivere questo valore, e Python non ti fermerà.

Enum in Python

Gli enum sono nomi leggibili che sono legati a un valore costante.

Per usare gli enum, importa Enum dal modulo della libreria standard enum:

from enum import Enum

Poi puoi inizializzare un nuovo enum in questo modo:

class Stato(Enum):
    INATTIVO = 0
    ATTIVO = 1

Una volta fatto ciò, puoi far riferimento a Stato.INATTIVO e Stato.ATTIVO, che funzionano come costanti.

Se proviamo a stampare Stato.ATTIVO, ad esempio:

print(Stato.ATTIVO)

non verrà stampato 1, ma Stato.ATTIVO.

Lo stesso valore può essere raggiunto dal numero assegnato all'enum: print(Stato(1)) restituirà Stato.ATTIVO. Lo stesso vale per la notazione con parentesi quadre Stato['ATTIVO'].

Puoi ottenere il valore con Stato.ATTIVO.value.

E puoi ottenere la lista di tutti i valori possibili di un enum:

list(Stato) # [<Stato.INATTIVO: 0>, <Stato.ATTIVO: 1>]

E puoi contarli:

len(Stato) # 2

Input utente in Python

In una applicazione riga di comando Python puoi mostrare informazioni a un utente usando la funzione print():

nome = "Roger"
print(nome)

Puoi anche accettare un input utente con input():

print('Quanti hanni hai?')
età = input()
print('Tu hai ' + età + ' anni')

Questo approccio prende l'input nel runtime, il che vuol dire che il programma interrompe l'esecuzione e attende finché l'utente non digita qualcosa e preme il tasto Invio.

Puoi anche fare un'elaborazione più complessa dell'input e accettare un input al momento della chiamata, e vedremo come farlo più avanti.

Questo funziona per applicazioni da riga di comando, mentre altri tipi di applicazioni hanno bisogno di un modo diverso per accettare degli input.

Istruzioni di controllo in Python

Avendo a che fare con booleani e, in particolare, espressioni che restituiscono booleani, puoi prendere decisioni e seguire strade differenti a seconda che abbiano valore True o False.

In Python lo si fa con l'istruzione if:

condizione = True

if condizione == True:
    # fai qualcosa

Quando la condizione viene valutata True, come nel caso qui sopra, il suo blocco viene eseguito.

Cos'è un blocco? Un blocco è una parte che è indentata sulla destra di un livello (di solito 4 spazi):

condizione = True

if condizione == True:
    print("La condizione")
    print("era vera")

Il blocco può essere formato da una singola riga come da più righe e termina quando il codice ritorna al livello di indentazione precedente:

condizione = True

if condizione == True:
    print("La condizione")
    print("era vera")

print("Fuori dal blocco if")

In combinazione con if, puoi avere un blocco else che viene eseguito se la condizione di if risulta essere False:

condizione = True

if condizione == True:
    print("La condizione")
    print("era vera")
else:
    print("La condizione")
    print("era falsa")

E puoi avere un if insieme a un elif che viene eseguito se la condizione precedente è False:

condizione = True
nome = "Roger"

if condizione == True:
    print("La condizione")
    print("era vera")
elif nome == "Roger":
    print("Ciao Roger")
else:
    print("La condizione")
    print("era falsa")

Il secondo blocco in questo caso viene eseguito se la condizione è False e il valore della variabile nome è "Roger".

All'interno di un'istruzione if è possibile avere solo un if e un else, ma gli elif possono essere multipli:

condizione = True
nome = "Roger"

if condizione == True:
    print("La condizione")
    print("era vera")
elif nome == "Roger":
    print("Ciao Roger")
elif nome == "Syd":
    print("Ciao Syd")
elif nome == "Flavio":
    print("Ciao Flavio")
else:
    print("La condizione")
    print("era falsa")

if ed else possono usati anche in una formattazione in riga, che ci permette di restituire un valore o un altro in base a una condizione.

Ad esempio:

a = 2
risultato = 2 if a == 0 else 3
print(risultato) # 3

Liste in Python

Le liste sono delle strutture di dati essenziali in Python.

Ti permettono di raggruppare insieme più valori che fanno riferimento a un nome comune.

Ad esempio:

cani = ["Roger", "Syd"]

Una lista può contenere valori di diverso tipo:

oggetti = ["Roger", 1, "Syd", True]

Puoi verificare se un oggetto è contenuto in una lista usando l'operatore in:

print("Roger" in oggetti) # True

È possibile anche definire una lista vuota:

oggetti = []

Puoi fare riferimento agli oggetti in una lista usando i loro indici, partendo da zero:

oggetti[0] # "Roger"
oggetti[1] # 1
oggetti[3] # True

Usando la stessa notazione puoi cambiare il valore archiviato a uno specifico indice:

oggetti[0] = "Roger"

Puoi anche usare il metodo index():

oggetti.index(0) # "Roger"
oggetti.index(1) # 1

Come per le stringhe, usare un indice negativo fa partire la ricerca dalla fine:

oggetti[-1] # True

Puoi estrarre anche parte di una lista usando la sintassi dello slicing:

oggetti[0:2] # ["Roger", 1]
oggetti[2:] # ["Syd", True]

E ottenere il numero di oggetti contenuti in una lista usando la funzione globale len(), la stessa che abbiamo usato per ottenere la lunghezza di una stringa:

len(oggetti) #4

Puoi aggiungere oggetti alla lista usando il metodo per liste append():

oggetti.append("Test")

o il metodo extend():

oggetti.extend(["Test"])

Puoi anche usare l'operatore +=:

oggetti += ["Test"]

# oggetti ora è ['Roger', 1, 'Syd', True, 'Test']
Tip: con extend() o += non dimenticare le parentesi quadre. Non scrivere oggetti += "Test" o oggetti.extend("Test") oppure Python aggiungerà 4 caratteri individuali alla lista, e otterrai ['Roger', 1, 'Syd', True, 'T', 'e', 's', 't']

Per rimuovere un oggetto puoi usare il metodo remove():

oggetti.remove("Test")

Per aggiungere elementi multipli puoi usare:

oggetti += ["Test1", "Test2"]

#oppure

oggetti.extend(["Test1", "Test2"])

Questi aggiungono gli oggetti alla fine della lista.

Per aggiungere un oggetto in mezzo a una lista, a un indice specifico, utilizza il metodo insert():

oggetti.insert("Test", 1) # aggiunge "Test" all'indice 1

E per aggiungere più elementi in corrispondenza di uno specifico indice, hai bisogno di usare lo slicing:

oggetti[1:1] = ["Test1", "Test2"]

Il metodo sort() viene usato per ordinare una lista:

oggetti.sort()
Tip: sort() funzionerà solo se la lista contiene valori che possono essere confrontati. Stringhe e interi, ad esempio, non possono essere confrontati, e se ci provi otterrai l'errore TypeError: '<' not supported between instances of 'int' and 'str'.

sort() ordina prima le lettere maiuscole e poi le minuscole. Per ovviare a questo problema, utilizza invece:

oggetti.sort(key=str.lower)

Ordinare una lista ne modifica il contenuto originario. Per evitarlo, puoi copiare il contenuto della lista usando:

copia_oggetti = oggetti[:]

o usando la funzione globale sorted():

print(sorted(oggetti, key=str.lower))

che restituirà una nuova lista ordinata invece di modificare quella originaria.

Tuple in Python

Le tuple sono delle altre strutture di dati fondamentali in Python.

Ti permettono di creare gruppi immutabili di oggetti. Questo vuol dire che una volta che una tupla è stata creata non può essere modificata. Non puoi aggiungere o rimuovere oggetti.

Sono create in modo simile alle liste, ma usando le parentesi tonde anziché quadre:

nomi = ("Roger", "Syd")

Una tupla è ordinata, come una lista, quindi puoi accedere ai suoi valori facendo riferimento all'indice:

nomi[0] # "Roger"
nomi[1] # "Syd"

Puoi anche utilizzare il metodo index():

nomi.index('Roger') # 0
nomi.index('Syd')   # 1

Come per stringhe e liste, un indice negativo fa partire il conteggio dalla fine:

nomi[-1] # Syd

E puoi controllare se un oggetto è contenuto in una tupla con l'operatore in:

print("Roger" in nomi) # True

Puoi anche estrarre parte di una tupla tramite slicing:

nomi[0:2] # ('Roger', 'Syd')
nomi[1:] # ('Syd',)

Per ottenere il numero di oggetti in una tupla puoi usare la funzione globale len(), la stessa che abbiamo usato per stringhe e liste:

len(nomi) #2

Puoi creare una versione ordinata di una tupla con la funzione globale sorted():

sorted(nomi)

Puoi creare una nuova tupla da una esistente usando l'operatore +:

nuova_tupla = nomi + ("Vanille", "Tina")

Dizionari in Python

I dizionari sono strutture di dati molto importanti in Python.

Mentre le liste ti permettono di creare collezioni di valori, i dizionari contengono collezioni di coppie chiave-valore.

Ecco un esempio di dizionario con una coppia chiave-valore:

cane = { 'nome': 'Roger' }

La chiave può essere un qualsiasi valore immutabile come una stringa, un numero o una tupla. Il valore può essere ciò che desideri.

Un dizionario può contenere coppie multiple chiave-valore:

cane = { 'nome': 'Roger', 'età': 8 }

Puoi accedere ai valori delle singole chiavi usando questa notazione:

cane['nome'] # 'Roger'
cane['età']  # 8

Usando la stessa notazione, è possibile cambiare il valore memorizzato in una specifica chiave:

cane['nome'] = 'Syd'

Un altro modo per accedere a un valore è tramite il metodo get(), che ha un'opzione per aggiungere un valore di default:

cane.get('nome') # 'Roger'
cane.get('test', 'default') # 'default'

Il metodo pop() recupera il valore di una chiave per poi cancellare l'oggetto dal dizionario:

cane.pop('nome') # 'Roger'

Il metodo popitem() recupera e rimuove l'ultima coppia chiave-valore inserita nel dizionario:

cane.popitem()

Puoi controllare se una chiave è contenuta in un dizionario con l'operatore in:

'nome' in cane # True

Per ottenere una lista con le chiavi di un dizionario puoi usare il metodo keys(), passando il suo risultato al costruttore list():

list(cane.keys()) # ['nome', 'età']

Per ottenere i valori puoi usare il metodo values(), e per le coppie chiave-valore in forma di tupla con il metodo items():

print(list(cane.values()))
# ['Roger', 8]

print(list(cane.items()))
# [('nome', 'Roger'), ('età', 8)]

Puoi ottenere la lunghezza di un dizionario con la funzione globale len(), la stessa usata per ottenere la lunghezza di una stringa o il numero di elementi di una lista:

len(cane) #2

Puoi aggiungere nuove coppie chiave-valore nel dizionario in questo modo:

cane['cibo preferito'] = 'carne'

E puoi rimuovere coppie chiave-valore da un dizionario con l'istruzione del:

del cane['cibo preferito']

Per copiare un dizionario puoi usare il metodo copy():

copia_cane = cane.copy()

Set in Python

I set sono altre strutture di dati importanti in Python.

Possiamo dire che funzionano come delle tuple, ma non sono ordinate e sono mutabili.

Oppure possiamo dire che funzionano come i dizionari, ma non hanno chiavi.

Possiedono anche una versione immutabile, chiamata frozenset.

Puoi creare un set usando questa sintassi:

nomi = {"Roger", "Syd"}

I set funzionano bene quando pensi a loro come a degli insiemi matematici.

Puoi ottenere l'intersezione di due set:

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

intersezione = set1 & set2 #{'Roger'}

L'unione di due set:

set1 = {"Roger", "Syd"}
set2 = {"Luna"}

unione = set1 | set2
#{'Syd', 'Luna', 'Roger'}

E la differenza tra due set:

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

differenza = set1 - set2 #{'Syd'}

Puoi controllare se un set è un sovrainsieme di un altro (e naturalmente anche se è un sottoinsieme):

set1 = {"Roger", "Syd"}
set2 = {"Roger"}

isSuperset = set1 > set2 # True

Puoi contare gli oggetti contenuti in un set con la funzione globale len():

nomi = {"Roger", "Syd"}
len(nomi) # 2

Puoi ottenere una lista degli oggetti in un set passando il set al costruttore list():

nomi = {"Roger", "Syd"}
list(nomi) #['Syd', 'Roger']

Puoi verificare se un oggetto è contenuto in un set con l'operatore in:

print("Roger" in nomi) # True

Funzioni in Python

Una funzione ci permette di creare un insieme di istruzioni che possiamo eseguire all'occorrenza.

Le funzioni sono essenziali in Python e in molti altri linguaggi di programmazione. Ci aiutano a creare programmi utili, perché ci permettono di decomporre un programma in parti gestibili e migliorano la leggibilità e il riutilizzo del codice.

Ecco l'esempio di una funzione chiamata ciao che stampa "Ciao!":

def ciao():
    print('Ciao!')

Questa è la definizione della funzione. C'è un nome (ciao) e un corpo, l'insieme di istruzioni, che è la parte che segue i due punti ed è indentata di un livello sulla destra.

Per eseguire questa funzione, dobbiamo invocarla con questa sintassi:

ciao()

Possiamo eseguirla una o più volte.

Il nome della funzione, ciao, è molto importante. Dovrebbe essere descrittivo, così che chiunque possa immaginare cosa fa la funzione.

Una funzione può accettare uno o più parametri:

def ciao(nome):
    print('Ciao ' + nome + '!')

In questo caso, chiamiamo la funzione passando un argomento:

ciao('Roger')
Chiamiamo parametri i valori accettati dalla funzione nella definizione della funzione, e argomenti i valori che passiamo alla funzione quando la chiamiamo. È comune fare confusione riguardo questa distinzione.

Un parametro può avere un valore di default che è applicato se non viene specificato:

def ciao(nome='amico mio'):
    print('Ciao ' + nome + '!')

ciao()
#Ciao amico mio!

Ecco come è possibile accettare più parametri:

def ciao(nome, età):
    print('Ciao ' + nome + ', tu hai ' + str(età) + ' anni!')

In questo caso, chiamiamo la funzione passandole un insieme di argomenti:

ciao('Roger', 8)

I parametri sono passati come riferimento. Tutti i tipi in Python sono degli oggetti, ma alcuni sono immutabili, inclusi interi, booleani, float, stringhe e tuple. Questo significa che quando li passiamo come parametri, il loro valore viene modificato nella funzione senza riflettersi al suo esterno:

def cambio(valore):
    valore = 2

val = 1
cambio(val)

print(val) #1

Se passi un oggetto che non è immutabile e cambi una delle sue proprietà, il cambiamento si rifletterà anche fuori dalla funzione.

Una funzione può restituire un valore usando l'istruzione return. Ad esempio, in questo caso restituiamo il nome del parametro nome:

def ciao(nome):
    print('Ciao ' + nome + '!')
    return nome

Quando la funzione incontra l'istruzione return, si ferma.

Possiamo omettere il valore:

def ciao(nome):
    print('Ciao ' + nome + '!')
    return

Possiamo avere un'istruzione return all'interno di un condizionale, che è un modo comune per terminare una funzione se non si verifica una condizione iniziale:

def ciao(nome):
    if not nome:
        return
    print('Ciao ' + nome + '!')

Se chiamiamo la funzione passandole un valore che viene valutato come False, come una stringa vuota, la funzione termina prima di raggiungere l'istruzione print().

Possiamo restituire più valori separandoli con una virgola:

def ciao(nome):
    print('Ciao ' + nome + '!')
    return nome, 'Roger', 8

In questo caso, chiamando ciao('Syd') otteniamo come valore di ritorno una tupla contenente 3 valori: ('Syd', 'Roger', 8).

Oggetti in Python

In Python, tutto è un oggetto.

Perfino i valori di tipi fondamentali primitivi (interi, stringhe, float...) sono oggetti. Le liste sono oggetti, così come tuple, dizionari e tutto il resto.

Gli oggetti hanno attributi e metodi a cui si può accedere tramite la sintassi con il punto.

Ad esempio, proviamo a definire una nuova variabile di tipo int:

età = 8

età ora ha accesso alle proprietà e ai metodi definiti per tutti gli oggetti int.

Questo include, ad esempio, l'accesso alle parti reale e immaginaria del numero:

print(età.real) # 8
print(età.imag) # 0

print(età.bit_length()) #4

# il metodo bit_length() restituisce il numero di bit necessari per rappresentare il numero in notazione binaria

Una variabile che contiene una lista ha accesso a un insieme differente di metodi:

oggetti = [1, 2]
oggetti.append(3)
oggetti.pop()

I metodi dipendono dal tipo di valore.

La funzione globale id() fornita da Python ti permette di analizzare la posizione in memoria di un particolare oggetto.

id(età) # 140170065725376
Il tuo valore sarà diverso – lo sto mostrando soltanto come esempio.

Se assegni un valore diverso a una variabile, la sua posizione cambierà, perché il contenuto della variabile è stato sostituito da un altro valore conservato in un'altra posizione nella memoria:

età = 8

print(id(età)) # 140535918671808

età = 9

print(id(età)) # 140535918671840

Ma se modifichi l'oggetto usando i suoi metodi, la posizione resterà la stessa:

oggetti = [1, 2]

print(id(oggetti)) # 140093713593920

oggetti.append(3)

print(oggetti) # [1, 2, 3]
print(id(oggetti)) # 140093713593920

La posizione cambia soltanto se riassegni alla variabile un altro valore.

Alcuni oggetti sono mutabili, mentre altri sono immutabili. Questo dipende dall'oggetto stesso.

Se un oggetto possiede dei metodi che ne cambiano il contenuto, allora è mutabile. In caso contrario, è immutabile.

La maggior parte dei tipi definiti in Python è immutabile. Ad esempio, un int è immutabile. Non ci sono metodi per cambiarne il valore e se incrementi il valore usando:

età = 8
età = età + 1

#oppure

età += 1

e poi controlli con id(età), troverai che età punta a una posizione diversa in memoria. Il valore originale non è stato modificato, siamo passati a un altro valore.

Loop in Python

I loop sono una parte essenziale della programmazione.

In Python abbiamo 2 tipi di loop: while e for.

Loop while in Python

I loop while sono definiti usando la parola chiave while e ripetono il loro blocco di codice finché la condizione non è valutata come False:

condizione = True
while condizione == True:
    print("La condizione è vera")

Questo è un loop infinito. Non termina mai.

Fermiamo il loop dopo la prima iterazione:

condizione = True
while condizione == True:
    print("La condizione è vera")
    condizione = False

print("Dopo il loop")

In questo caso, la prima iterazione viene eseguita perché la condizione è valutata come True. Alla seconda iterazione, la condizione diventa False, quindi il controllo prosegue all'istruzione successiva dopo il loop.

È comune avere un contatore per fermare le iterazioni dopo un certo numero di cicli:

count = 0
while count < 10:
    print("La condizione è vera")
    count = count + 1

print("Dopo il loop")

Loop for in Python

Usando un loop for possiamo dire a Python di eseguire un blocco un numero predeterminato di volte, in anticipo e senza bisogno di una variabile separata e un condizionale per verificare il suo valore.

Ad esempio, possiamo iterare sugli oggetti di una lista:

oggetti = [1, 2, 3, 4]
for oggetto in oggetti:
    print(oggetto)

O iterare un numero specifico di volte usando la funzione range():

for oggetto in range(4):
    print(oggetto)

range(4) crea una sequenza che parte da 0 e contiene 4 oggetti: [0, 1, 2, 3].

Per ottenere gli indici, devi inserire la sequenza nella funzione enumerate():

oggetti = [1, 2, 3, 4]
for indice, oggetto in enumerate(oggetti):
    print(indice, oggetto)

break e continue in Python

Sia i loop while che for possono essere interrotti all'interno del blocco, usando due parole chiave speciali: break e continue.

continue interrompe l'iterazione corrente e dice a Python di passare alla successiva.

break interrompe l'intero loop e passa all'istruzione successiva dopo la fine del loop.

Il primo esempio qui sotto stampa 1, 3, 4. Il secondo stampa 1:

oggetti = [1, 2, 3, 4]
for oggetto in oggetti:
    if oggetto == 2:
        continue
    print(oggetto)
oggetti = [1, 2, 3, 4]
for oggetto in oggetti:
    if oggetto == 2:
        break
    print(oggetto)

Classi in Python

In aggiunta ai tipi forniti da Python, possiamo dichiarare delle classi e, da queste, istanziare degli oggetti.

Un oggetto è una istanza di una classe. Una classe è un tipo di oggetto.

Possiamo definire una classe in questo modo:

class <NomeClasse>:
    # la mia classe

Ad esempio, definiamo la classe Cane:

class Cane:
    # la classe Cane

Una classe può definire dei metodi:

class Cane:
    # la classe Cane
    def abbaia(self):
        print('BAU!')
self come argomento del metodo punta all'istanza dell'oggetto corrente e deve essere specificato durante la definizione di un metodo.

Creiamo una istanza di una classe, un oggetto, usando questa sintassi:

roger = Cane()

Ora roger è un nuovo oggetto di tipo Cane.

Se esegui:

print(type(roger))

Otterrai <class '__main__.Cane'>

Un tipo speciale di metodo, __init__(), è detto costruttore e possiamo usarlo per inizializzare una o più proprietà quando creiamo un nuovo oggetto di una classe:

class Cane:
    # la classe Cane
    def __init__(self, nome, età):
        self.nome = nome
        self.età = età

    def abbaia(self):
        print('BAU!')

Lo usiamo in questo modo:

roger = Cane('Roger', 8)
print(roger.nome) # Roger
print(roger.età)  # 8

roger.abbaia() # BAU!

Una caratteristica importante delle classi è l'ereditarietà.

Possiamo creare una classe Animale con un metodo cammina():

class Animale:
    def cammina(self):
        print('Cammina..')

e la classe Cane può ereditare da Animale:

class Cane(Animale):
    def abbaia(self):
        print('BAU!')

Adesso, quando creiamo un nuovo oggetto della classe Cane, avrà il metodo cammina(), ereditato da Animale:

roger = Cane()
roger.cammina() # Cammina..
roger.abbaia() # BAU!

Moduli in Python

Ogni file Python è un modulo.

Puoi importare un modulo da altri file. Ciò è alla base di ogni programma di complessità moderata, dato che promuove un'organizzazione ragionevole e il riutilizzo del codice.

In un tipico programma Python, un file agisce come punto di accesso. Gli altri file sono moduli ed espongono funzioni che possiamo chiamare da altri file.

Il file cane.py contiene questo codice:

def abbaia():
    print('BAU!')

Possiamo importare questa funzione da un altro file usando import. Una volta fatto ciò, possiamo fare riferimento alla funzione usando la notazione con il punto, cane.abbaia():

import cane

cane.abbaia()

Oppure possiamo usare la sintassi from .. import e chiamare direttamente la funzione:

from cane import abbaia

abbaia()

La prima strategia ci permette di caricare tutto ciò che è definito in un file.

Con la seconda prendiamo solo ciò che ci serve.

Questi moduli sono specifici per un programma e come importarli dipende dalla posizione del file nel filesystem.

Immagina di mettere cane.py nella sotto-cartella lib.

In questa cartella, devi creare un file vuoto chiamato __init__.py. Questo dice a Python che la cartella contiene dei moduli.

Ora puoi scegliere – puoi importare cane da lib:

from lib import cane

cane.abbaia()

o puoi riferirti a una specifica funzione del modulo cane importandola da lib.cane:

from lib.cane import abbaia

abbaia()

La libreria standard di Python

Python ha un sacco di funzionalità integrate nella sua libreria standard.

La libreria standard è una collezione enorme di ogni sorta di utilità, dalla matematica al debugging alla creazione di interfacce utente.

Qui puoi trovare la lista completa dei moduli della libreria standard: https://docs.python.org/3/library/index.html

Alcuni dei moduli più importanti sono:

  • math per utilità di matematica
  • re per le espressioni regolari
  • json per lavorare con JSON
  • datetime per lavorare con le date
  • sqlite3 per usare SQLite
  • os per utilità del sistema operativo
  • random per la generazione di numeri casuali
  • statistics per utilità di statistica
  • requests per svolgere richieste di rete HTTP
  • http per creare server HTTP
  • urllib per gestire URL

Introduciamo l'uso di un modulo della libreria standard. Sai già come usare moduli creati da te, importandoli da altri file nella cartella del programma.

Vale la stessa cosa per i moduli forniti dalla libreria standard:

import math

math.sqrt(4) # 2.0

oppure

from math import sqrt

sqrt(4) # 2.0

Esploreremo presto i moduli più importanti singolarmente per capire come utilizzarli.

La guida allo stile di Python PEP8

Quando scrivi del codice, dovresti attenerti alle convenzioni del linguaggio di programmazione che usi.

Se impari le convenzioni di nomenclatura e formattazione corrette dall'inizio, sarà più facile leggere il codice scritto da altre persone, e gli altri troveranno facile leggere il tuo codice.

Python definisce le sue convenzioni nella guida allo stile PEP8. PEP sta per Python Enhancement Proposals ed è dove avvengono tutti i miglioramenti e le discussioni sul linguaggio Python.

Ci sono molte proposte PEP, tutte disponibili su https://www.python.org/dev/peps/.

PEP8 è una delle prime e anche una delle più importanti. Definisce la formattazione e anche alcune regole su come scrivere Python in modo "pythonico".

Qui puoi leggere il contenuto integrale: https://www.python.org/dev/peps/pep-0008/ mentre questo è un breve sommario dei punti importanti da cui iniziare:

  • Indenta usando gli spazi, non tab
  • Indenta usando 4 spazi
  • I file Python sono codificati in UTF-8
  • Usa al massimo 80 colonne per il tuo codice
  • Scrivi ogni istruzione sulla propria riga
  • Funzioni, nomi di variabili e di file sono minuscoli, con un trattino basso tra le parole (snake_case)
  • I nomi delle classi iniziano con una lettera maiuscola e anche le diverse parole che li compongono iniziano con una maiuscola (CamelCase)
  • I nomi dei pacchetti sono minuscoli e non hanno trattini bassi tra le parole
  • Le variabili che non devono cambiare (costanti) sono scritte in maiuscolo
  • I nomi delle variabili devono essere esplicativi
  • Aggiungi commenti utili ed evita i commenti ovvi
  • Aggiungi spazi intorno agli operatori
  • Non usare spazi non necessari
  • Aggiungi una riga vuota prima di una funzione
  • Aggiungi una riga vuota tra i metodi in una classe
  • All'interno di funzioni/metodi, delle righe vuote possono essere usate per separare blocchi di codice e migliorare la leggibilità

Debugging in Python

Il debugging è una delle migliori abilità che puoi acquisire, visto che ti tornerà utile in molte situazioni di difficoltà.

Ogni linguaggio possiede il proprio debugger. Python ha pdb, disponibile tramite la libreria standard.

Puoi fare debug aggiungendo un breakpoint nel tuo codice:

breakpoint()
Puoi aggiungere più breakpoint se necessario.

Quando l'interprete di Python arriva al breakpoint nel tuo codice, si fermerà e ti dirà qual è l'istruzione successiva da eseguire.

Poi puoi fare diverse cose.

Puoi digitare il nome di una variabile per esaminarne il valore.

Puoi premere n per passare alla riga successiva della funzione corrente. Se il codice chiama delle funzioni, il debugger non vi accede e le considera come "scatole chiuse".

Puoi premere s per passare alla riga successiva della funzione corrente. Se la riga successiva è una funzione, il debugger vi accede e puoi eseguire un'istruzione alla volta.

Puoi premere c per continuare l'esecuzione del programma normalmente, senza doverlo fare per ogni step.

Puoi premere q per fermare l'esecuzione del programma.

Il debugging è utile per valutare il risultato di un'istruzione, ed è utile soprattutto sapere come utilizzarlo quando hai a che fare con iterazioni complesse o algoritmi da sistemare.

Visibilità delle variabili in Python

Quando dichiari una variabile, questa è visibile in alcune parti del programma, a seconda di dove l'hai dichiarata.

Se la dichiari fuori da una funzione, la variabile è visibile da tutto il codice che viene eseguito dopo la dichiarazione, incluse le funzioni:

età = 8

def test():
    print(età)

print(età) # 8
test() # 8

Questa viene detta variabile globale.

Se definisci una variabile all'interno di una funzione, sarà una variabile locale e sarà visibile soltanto all'interno della funzione. Non è possibile raggiungerla dall'esterno:

def test():
    età = 8
    print(età)

test() # 8

print(età)
# NameError: name 'età' is not defined

Come accettare argomenti dalla riga di comando in Python

Python offre diversi modi per gestire gli argomenti passati quando invochiamo un programma dalla riga di comando.

Finora abbiamo eseguito i programmi da un REPL o usando:

python <nomefile>.py

Quando lo fai, puoi passare argomenti aggiuntivi e opzioni, in questo modo:

python <nomefile>.py <argomento1>
python <nomefile>.py <argomento1> <argomento2>

Un modo semplice per gestire questi argomenti è usare il modulo sys della libreria standard.

Puoi ottenere gli argomenti passati nella lista sys.argv:

import sys
print(len(sys.argv))
print(sys.argv)

La lista sys.argv contiene come primo oggetto il nome del file che è stato eseguito, ad esempio ['main.py'].

Questo è un modo semplice, ma occorre molto lavoro. Hai bisogno di validare gli argomenti, assicurarti che il loro tipo sia corretto e hai bisogno di stampare un feedback per gli utenti se non stanno usando il programma correttamente.

Per aiutarti, Python fornisce un altro pacchetto nella libreria standard: argparse.

Prima importa argparse e chiama argparse.ArgumentParser(), passando la descrizione del tuo programma:

import argparse

parser = argparse.ArgumentParser(
    description='Questo programma stampa i nomi dei miei cani'
)

Poi procedi ad aggiungere gli argomenti che vuoi che accetti.
Ad esempio, in questo programma accettiamo un'opzione -c per passare un colore, in questo modo: python programma.py -c rosso

import argparse

parser = argparse.ArgumentParser(
    description='Questo programma stampa un colore esadecimale'
)

parser.add_argument('-c', '--colore', metavar='colore', required=True, help='il colore da cercare')

argomenti = parser.parse_args()

print(argomenti.colore) # 'rosso'

Se l'argomento non è specificato, il programma genera un errore:

➜  python python programma.py
usage: programma.py [-h] -c colore
programma.py: error: the following arguments are required: -c

Puoi impostare un'opzione per avere un insieme specifico di valori, usando choices:

parser.add_argument('-c', '--colore', metavar='colore', required=True, choices={'rosso','giallo'}, help='il colore da cercare')
➜  python python programma.py -c blu
usage: programma.py [-h] -c colore
programma.py: error: argument -c/--colore: invalid choice: 'blu' (choose from 'giallo', 'rosso')

Esistono molte opzioni, ma queste sono quelle fondamentali.

Ed esistono anche pacchetti di comunità che forniscono questa funzionalità come Click e Python Prompt Toolkit.

Funzioni lambda in Python

Le funzioni lambda (anche dette funzioni anonime) sono piccole funzioni che non hanno un nome e hanno una sola espressione nel loro corpo.

In Python sono definite usando la parola chiave lambda:

lambda <argomenti> : <espressione>

Il corpo deve essere formato da una singola espressione – un'espressione, non un'istruzione.

Questa differenza è importante. Un'espressione restituisce un valore, un'istruzione no.

L'esempio più semplice di una funzione lamba è una funzione che raddoppia il valore di un numero:

lambda num : num * 2

Le funzioni lambda possono accettare più argomenti:

lambda a, b : a * b

E non possono essere invocate direttamente, ma possono essere assegnate a delle variabili:

moltiplica = lambda a, b : a * b

print(moltiplica(2, 2)) # 4

L'utilità delle funzioni lambda scaturisce dalla combinazione con altre funzionalità di Python, ad esempio in combinazione con map(), filter() e reduce().

Ricorsione in Python

Una funzione in Python può chiamare sé stessa. Questo concetto è alla base della ricorsione ed è piuttosto utile in molte situazioni.

Il modo più comune di spiegare la ricorsione è usando il calcolo di un fattoriale.

Il fattoriale di un numero è il numero n moltiplicato per n-1, moltiplicato per n-2... e così via, fino ad arrivare al numero 1:

3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120

Usando la ricorsione possiamo scrivere una funzione che calcola il fattoriale di un numero qualsiasi:

def fattoriale(n):
    if n == 1: return 1
    return n * fattoriale(n-1)

print(fattoriale(3)) #   6
print(fattoriale(4)) #  24
print(fattoriale(5)) # 120

Se all'interno della funzione fattoriale() chiami fattoriale(n) invece di fattoriale(n-1), causerai una ricorsione infinita. Di default, Python fermerà le ricorsioni a 1000 chiamate, e quando questo limite viene raggiunto otterrai l'errore RecursionError.

La ricorsione è utile in molte occasioni e ti aiuta a semplificare il tuo codice quando non c'è un modo ottimale per farlo, quindi è bene conoscere questa tecnica.

Funzioni annidate in Python

Le funzioni in Python possono essere annidate in altre funzioni.

Questo è utile per creare utilità che servono all'interno di una funzione ma non all'esterno.

Potresti chiederti: perché dovrei "nascondere" questa funzione se non fa del male a nessuno?

Prima di tutto, perché è sempre meglio nascondere funzionalità che sono locali per una funzione e non utili altrove.

E poi perché possiamo fare uso di chiusure (di più su questo argomento in seguito).

Ecco un esempio:

def parlare(frase):
    def dire(parola):
        print(parola)

    parole = frase.split(' ')
    for parola in parole:
        dire(parola)

parlare('Sto uscendo da casa')

Se vuoi accedere a una variabile definita nella funzione esterna dalla funzione interna, devi prima dichiararla come nonlocal:

def conteggio():
    conto = 0

    def incremento():
        nonlocal conto
        conto = conto + 1
        print(conto)

    incremento()

conto()

Questo è particolarmente utile con le chiusure, come vedremo nella prossima sezione.

Chiusure in Python

Se restituisci una funzione annidata da una funzione, la funzione annidata ha accesso alle variabili definite nella funzione, anche se non è più attiva.

Ecco un semplice esempio:

def contatore():
    conto = 0

    def incremento():
        nonlocal conto
        conto = conto + 1
        return conto

    return incremento

incremento = contatore()

print(incremento()) # 1
print(incremento()) # 2
print(incremento()) # 3

Restituiamo la funzione interna incremento() che ha ancora accesso allo stato della variabile conto anche se la funzione contatore() è terminata.

Decoratori in Python

I decoratori sono un modo per cambiare, migliorare o alterare in qualsiasi modo il funzionamento di una funzione.

I decoratori sono definiti dal simbolo @ seguito dal nome del decoratore, prima della definizione della funzione.

Esempio:

@logtime
def ciao():
    print('Ciao!')

A questa funzione ciao è stato assegnato il decoratore logtime.

Ogni volta che chiamiamo ciao(), sarà chiamato anche il decoratore.

Un decoratore è una funzione che prende una funzione come parametro, avvolge la funzione in una funzione interna che effettua un'operazione specifica e restituisce la funzione interna. In altre parole:

def logtime(funzione):
    def wrapper():
        # fai qualcosa prima
        val = funzione()
        # fai qualcosa dopo
        return val
    return wrapper

Docstring in Python

La documentazione è incredibilmente importante, non solo per comunicare alle altre persone qual è lo scopo di funzioni/classi/metodi/moduli, ma anche per te.

Quando ritorni su del codice dopo 6 o 12 mesi, potresti non ricordare tutto quello che avevi in testa. A questo punto, leggere il tuo codice e capire cosa dovrebbe fare potrebbe essere più difficile.

I commenti sono un modo per aiutare te stesso (e gli altri):

# questo è un commento

num = 1 # questo è un altro commento

Un altro modo è usare delle docstring.

L'utilità delle docstring è che seguono delle convenzioni, pertanto possono essere processate automaticamente.

Questo è il modo di definire una docstring per una funzione:

def incrementa(n):
    """Incrementa un numero"""
    return n + 1

Questo è il modo di definire una docstring per una classe e un metodo:

class Cane:
    """Una classe che rappresenta un cane"""
    def __init__(self, nome, età):
        """Istanzia un nuovo cane"""
        self.nome = nome
        self.età = età

    def abbaia(self):
        """Fai abbaiare il cane"""
        print('BAU!')

Descrivi un modulo aggiungendo una docstring in cima al file, ad esempio per cane.py:

"""Modulo cane

Questo modulo fa questo... bla bla bla e ha le seguenti classi:

- Cane
...
"""

class Cane:
    """Una classe che rappresenta un cane"""
    def __init__(self, nome, età):
        """Istanzia un nuovo cane"""
        self.nome = nome
        self.età = età

    def abbaia(self):
        """Fai abbaiare il cane"""
        print('BAU!')

Le docstring possono occupare più righe:

def incrementa(n):
    """Incrementa
    un numero
    """
    return n + 1

Python le elaborerà e potrai usare la funzione globale help() per ottenere la documentazione di classi/metodi/funzioni/moduli.

Ad esempio, chiamando help(incrementa) otterrai:

Help on function incrementa in module
__main__:

incrementa(n)
    Incrementa
    un numero

Ci sono molti standard diversi per formattare le docstring e puoi scegliere di attenerti a quello che preferisci.

I preferisco lo standard di Google: https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings

Gli standard ti permettono di avere strumenti per estrarre le docstring e generare automaticamente della documentazione per il tuo codice.

Introspezione in Python

Funzioni, variabili e oggetti possono essere analizzati usando l'introspezione.

Usando la funzione globale help() possiamo ottenere la documentazione fornita in forma di docstring.

Poi, possiamo utilizzare la funzione print() per ottenere informazioni su una funzione:

def incrementa(n):
    return n + 1

print(incrementa)

# <function incrementa at 0x7f420e2973a0>

o un oggetto:

class Cane():
    def abbaia(self):
        print('BAU!')

roger = Cane()

print(roger)

# <__main__.Cane object at 0x7f42099d3340>

La funzione type() ci dà il tipo di un oggetto:

print(type(incrementa))
# <class 'function'>

print(type(roger))
# <class '__main__.Cane'>

print(type(1))
# <class 'int'>

print(type('test'))
# <class 'str'>

La funzione globale dir() ci permette di trovare tutti i metodi e gli attributi di un oggetto:

print(dir(roger))

# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bark']

La funzione globale id() ci mostra la posizione in memoria di un oggetto:

print(id(roger)) # 140227518093024
print(id(1))     # 140227521172384

Può essere utile per vedere se due variabili puntano allo stesso oggetto.

Il modulo inspect della libreria standard fornisce altri strumenti per avere informazioni su oggetti: https://docs.python.org/3/library/inspect.html

Annotazioni in Python

Python è dinamicamente tipizzato. Non dobbiamo specificare il tipo di una variabile, di un parametro di una funzione o del valore di ritorno di una funzione.

Le annotazioni ci permettono di farlo (facoltativamente).

Questa è una funzione senza annotazioni:

def incrementa(n):
    return n + 1

Questa è la stessa funzione con annotazioni:

def incrementa(n: int) -> int:
    return n + 1

Puoi annotare anche delle variabili:

conto: int = 0

Python ignorerà le annotazioni. Uno strumento separato chiamato mypy può essere eseguito indipendentemente, o integrato in un IDE come VS Code o PyCharm per controllare staticamente gli errori di tipo in automatico, mentre stai programmando. Ti aiuterà anche a individuare bug dovuti a discordanze di tipo ancora prima di eseguire il codice.

Un grande aiuto, soprattutto quando un software diventa grande ed è necessario un refactoring del codice.

Eccezioni in Python

È importante avere un modo per gestire gli errori e Python ci offre degli strumenti adatti a questo scopo.

Se includi delle righe in un blocco try::

try:
    # delle righe di codice

Nel caso in cui si verifichi un errore, Python ti avviserà e sarai in grado di determinare il tipo di errore usando un blocco except:

try:
    # delle righe di codice
except <ERRORE1>:
    # gestione <ERRORE1>
except <ERRORE2>:
    # gestione <ERRORE2>

Per individuare tutte le eccezioni puoi usare except senza nessun tipo di errore:

try:
    # delle righe di codice
except <ERRORE1>:
    # gestione <ERRORE1>
except:
    # trova tutte le eccezioni

Il blocco else è eseguito se non viene riscontrata nessuna eccezione:

try:
    # delle  righe di codice
except <ERRORE1>:
    # gestione <ERRORE1>
except <ERRORE2>:
    # gestione <ERRORE2>
else:
    # nessuna eccezione, il codice è stato eseguito con successo

Il blocco finally ti consente di svolgere delle operazioni in qualsiasi caso, indipendentemente dalla presenza o meno di un errore:

try:
    # delle  righe di codice
except <ERRORE1>:
    # gestione <ERRORE1>
except <ERRORE2>:
    # gestione <ERRORE2>
else:
    # nessuna eccezione, il codice è stato eseguito con successo
finally:
    # fai qualcosa in ogni caso

Lo specifico errore che può verificarsi dipende dall'operazione eseguita.

Ad esempio, se stai leggendo un file, potresti ottenere un EOFError. Se dividi un numero per zero vedrai ZeroDivisionError. Se invece hai un problema di conversione di tipo otterrai un TypeError.

Prova questo codice:

result = 2 / 0
print(result)

Il programma terminerà con un errore:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    result = 2 / 0
ZeroDivisionError: division by zero

e le righe di codice dopo l'errore non saranno eseguite.

Aggiungere l'operazione in un blocco try: ci consente di recuperare con grazia e continuare con il programma:

try:
    result = 2 / 0
except ZeroDivisionError:
    print('Non puoi dividere per zero!')
finally:
    result = 1

print(result) # 1

Puoi restituire delle eccezioni nel tuo codice usando l'istruzione raise:

raise Exception('Si è verificato un errore!')

Questo causa un'eccezione generica, che puoi intercettare così:

try:
    raise Exception('Si è verificato un errore!')
except Exception as error:
    print(error)

Puoi anche definire la tua classe di eccezioni, estendendola da Exception:

class EccezioneCaneNonTrovato(Exception):
    pass
pass qui significa "niente" e dobbiamo usarlo quando definiamo una classe senza metodi o una funzione senza codice.
try:
    raise EccezioneCaneNonTrovato()
except EccezioneCaneNonTrovato:
    print('Cane non trovato!')

L'istruzione with in Python

L'istruzione with è molto utile per semplificare il lavoro con la gestione delle eccezioni.

Ad esempio, lavorando con dei file, ogni volta che ne apriamo uno dobbiamo ricordarci di chiuderlo.

with rende questo processo trasparente.

Invece di scrivere:

nomefile = '/Users/flavio/test.txt'

try:
    file = open(nomefile, 'r')
    contenuto = file.read()
    print(contenuto)
finally:
    file.close()

Puoi scrivere:

nomefile = '/Users/flavio/test.txt'

with open(nomefile, 'r') as file:
    contenuto = file.read()
    print(contenuto)

In altre parole, abbiamo una gestione delle eccezioni implicita, dato che close() sarà chiamata automaticamente per noi.

with non è solo utile per lavorare con i file. L'esempio qui sopra è soltanto per introdurre le sue potenzialità.

Come installare pacchetti di terze parti in Python usando pip

La libreria standard di Python contiene un numero enorme di utilità che semplificano ciò di cui abbiamo bisogno per lo sviluppo con Python, ma niente è in grado di soddisfare ogni necessità.

Ecco perché aziende e singoli creano pacchetti e li rendono disponibili come software open source per l'intera comunità.

Questi moduli sono raccolti in un unico posto, il Python Package Index, disponibile su https://pypi.org, e possono essere installati sul tuo sistema usando pip.

Ci sono più di 270,000 pacchetti disponibili gratuitamente nel momento in cui scrivo.

Dovresti già avere pip installato se hai seguito le istruzioni di installazione di Python.

Installa qualsiasi pacchetto con il comando pip install:

pip install <pacchetto>

oppure, se stai avendo problemi, lo puoi eseguire anche con python -m:

python -m pip install <pacchetto>

Ad esempio, puoi installare il pacchetto requests, una popolare libreria HTTP:

pip install requests

e una volta fatto ciò, sarà disponibile per tutti i tuoi script Python, perché i pacchetti vengono installati globalmente.

La posizione esatta dipende dal sistema operativo.

Su macOS, con Python 3.9, la posizione è /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages.

Aggiorna un pacchetto alla sua ultima versione con:

pip install –U <pacchetto>

Installa una versione specifica di un pacchetto usando:

pip install <pacchetto>==<versione>

Disinstalla un pacchetto usando:

pip uninstall <pacchetto>

Mostra i dettagli di un pacchetto installato, tra cui versione, documentazione del sito e informazioni sull'autore usando:

pip show <pacchetto>

Comprensioni di lista in Python

Le comprensioni di lista sono un modo per creare liste in un modo molto conciso.

Supponi di avere una lista:

numeri = [1, 2, 3, 4, 5]

Puoi creare una nuova lista usando una comprensione di lista, composta dagli elementi della lista numeri elevati al quadrato:

numeri_al_quadrato = [n**2 for n in numeri]
# [1, 4, 9, 16, 25]

Le comprensioni di lista costituiscono una sintassi a volte preferita ai loop, visto che sono più leggibili quando le operazioni possono essere scritte su una sola riga:

numeri_al_quadrato = []
for n in numeri:
    numeri_al_quadrato.append(n**2)

e anche rispetto a map():

numeri_al_quadrato = list(map(lambda n : n**2, numeri))

Polimorfismo in Python

Il polimorfismo generalizza una funzionalità in modo che funzioni su tipi diversi. È un concetto importante della programmazione orientata agli oggetti.

Possiamo definire lo stesso metodo su classi diverse:

class Cane:
    def mangia():
        print('Mangia cibo per cani')

class Gatto:
    def mangia():
        print('Mangia cibo per gatti')

Poi, possiamo generare oggetti e chiamare il metodo mangia() indipendentemente dalla classe a cui appartiene l'oggetto, e otterremo risultati diversi:

animale1 = Cane()
animale2 = Gatto()

animale1.mangia()
animale2.mangia()

Costruiamo un'interfaccia generalizzata e non abbiamo bisogno di sapere che un animale è un Cane o un Gatto.

Overloading degli operatori in Python

L'overloading degli operatori è una tecnica avanzata che possiamo usare per rendere comparabili delle classi e per farle funzionare come degli operatori Python.

Prendiamo la classe Cane:

class Cane:
    # la classe Cane
    def __init__(self, nome, età):
        self.nome = nome
        self.età = età

E creiamo 2 oggetti Cane:

roger = Cane('Roger', 8)
syd = Cane('Syd', 7)

Possiamo usare l'overloading degli operatori per aggiungere un modo per confrontare questi 2 oggetti, in base alla proprietà età:

class Cane:
    # la classe Cane
    def __init__(self, nome, età):
        self.nome = nome
        self.età = età
    def __gt__(self, other):
        return True if self.età > other.età else False

Se provi a eseguire print(roger > syd) otterrai come risultato True.

Nello stesso modo in cui definiamo __gt__() (maggiore di, greater than), possiamo definire i seguenti metodi:

  • __eq__() per verificare l'uguaglianza
  • __lt__() per verificare se un oggetto dovrebbe essere considerato minore di un altro con l'operatore <
  • __le__() per minore o uguale (<=)
  • __ge__() per maggiore o uguale (>=)
  • __ne__() per la disuguaglianza(!=)

E poi ci sono i metodi per interagire con le operazioni aritmetiche:

  • __add__() corrisponde all'operatore +
  • __sub__() corrisponde all'operatore
  • __mul__() corrisponde all'operatore *
  • __truediv__() corrisponde all'operatore /
  • __floordiv__() corrisponde all'operatore //
  • __mod__() corrisponde all'operatore %
  • __pow__() corrisponde all'operatore **
  • __rshift__() corrisponde all'operatore >>
  • __lshift__() corrisponde all'operatore <<
  • __and__() corrisponde all'operatore &
  • __or__() corrisponde all'operatore |
  • __xor__() corrisponde all'operatore ^

Esiste anche qualche altro metodo per lavorare con gli operatori, ma adesso ti sei fatto un'idea.

Ambienti virtuali in Python

È comune avere più applicazioni Python in esecuzione su un sistema.

Quando le applicazioni richiedono lo stesso modulo, a un certo punto raggiungerai una situazione complicata in cui una app ha bisogno di una versione di un modulo e un'altra app ha bisogno di una versione differente dello stesso modulo.

Puoi ovviare a questa situazione, puoi usare degli ambienti virtuali.

Utilizzeremo venv. Altri strumenti come pipenv funzionano in modo simile.

Crea un ambiente virtuale usando:

python -m venv .venv

all'interno della cartella in cui vuoi iniziare un progetto, o dove ne esiste già uno.

Poi esegui:

source .venv/bin/activate
Usa source .venv/bin/activate.fish sulla shell Fish

Eseguire il programma attiverà l'ambiente virtuale di Python. In base alla tua configurazione potresti vedere anche dei cambi nel prompt del terminale.

Il mio è passato da

➜ folder

a

(.venv) ➜ folder

Adesso eseguendo pip userai questo ambiente virtuale invece di quello globale.

Conclusione

Grazie per aver letto questo manuale.

Spero che ti ispirerà a imparare di più su Python.

Nota: puoi ottenere le versioni PDF, ePub e Mobi di questo Manuale Python (versione originale inglese)