Introduzione a Python

Premessa

Ti diamo il benvenuto nel tutorial online di Google su Python. Si basa sul corso Python introduttivo offerto internamente. Come indicato nella pagina di configurazione, questo materiale riguarda Python 3.

Se stai cercando un corso MOOC complementare, prova quelli di Udacity e Coursera (introduzione alla programmazione [ principianti] o introduzione a Python). Infine, se cerchi un'esperienza di apprendimento online autonomo senza guardare video, prova quelle elencate alla fine di questo post: ognuna offre contenuti didattici e un interprete interattivo di Python con cui fare pratica. Che cos'è questo "interprete" di cui parli? Scoprilo nella prossima sezione.

Introduzione alla lingua

Python è un linguaggio dinamico e interpretato (compilato con bytecode). Nel codice sorgente non sono presenti dichiarazioni di tipo di variabili, parametri, funzioni o metodi. Il codice diventa breve e flessibile, ma perdi il controllo dei tipi in fase di compilazione del codice sorgente. Python monitora i tipi di tutti i valori in fase di runtime e segnala il codice che non ha senso durante l'esecuzione.

Un ottimo modo per capire come funziona il codice Python è eseguire l'interprete Python e digitare il codice direttamente al suo interno. Se ti poni una domanda come "Cosa succede se aggiungo un int a un list?", digitarla nell'interprete Python è un modo rapido e probabilmente il migliore per vedere cosa succede. Vedi di seguito per vedere cosa succede davvero.

$ python3        ## Run the Python interpreter
Python 3.X.X (XXX, XXX XX XXXX, XX:XX:XX) [XXX] on XXX
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 6       ## set a variable in this interpreter session
>>> a           ## entering an expression prints its value
6
>>> a + 2
8
>>> a = 'hi'    ## 'a' can hold a string just as well
>>> a
'hi'
>>> len(a)      ## call the len() function on a string
2
>>> a + len(a)  ## try something that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can only concatenate str (not "int") to str
>>> a + str(len(a))  ## probably what you really wanted
'hi2'
>>> foo         ## try something else that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'foo' is not defined
>>> ^D          ## type CTRL-d to exit (CTRL-z in Windows/DOS terminal)

Le due righe stampate da Python dopo aver digitato python e prima del prompt >>> ti informano sulla versione di Python in uso e su dove è stata compilata. Se la prima cosa stampata è "Python 3", questi esempi dovrebbero funzionare.

Come puoi vedere sopra, è facile fare esperimenti con variabili e operatori. Inoltre, l'interprete genera, o "lancia" nel gergo di Python, un errore di runtime se il codice tenta di leggere una variabile a cui non è stato assegnato un valore. Come C++ e Java, Python è sensibile alle maiuscole, quindi "a" e "A" sono variabili diverse. La fine di una riga indica la fine di un'istruzione, quindi, a differenza di C++ e Java, Python non richiede un punto e virgola alla fine di ogni istruzione. I commenti iniziano con un carattere "#" e si estendono fino alla fine della riga.

Codice sorgente Python

I file di origine Python utilizzano l'estensione ".py" e sono chiamati "moduli". Con un modulo Python hello.py, il modo più semplice per eseguirlo è con il comando shell "python hello.py Alice", che chiama l'interprete Python per eseguire il codice in hello.py, passando l'argomento della riga di comando "Alice". Consulta la pagina della documentazione ufficiale per conoscere tutte le diverse opzioni a tua disposizione quando esegui Python dalla riga di comando.

Ecco un programma hello.py molto semplice (tieni presente che i blocchi di codice sono delimitati rigorosamente utilizzando l'indentazione anziché le parentesi graffe; ne parleremo più avanti):

#!/usr/bin/python3

# import modules used here -- sys is a very standard one
import sys

# Gather our code in a main() function
def main():
    print('Hello there', sys.argv[1])
    # Command line args are in sys.argv[1], sys.argv[2] ...
    # sys.argv[0] is the script name itself and can be ignored

# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
    main()

L'esecuzione di questo programma dalla riga di comando è simile al seguente:

$ python3 hello.py Guido
Hello there Guido
$ ./hello.py Alice  ## without needing 'python3' first (Unix)
Hello there Alice

Importazioni, argomenti della riga di comando e len()

Le istruzioni più esterne in un file Python, o "modulo", eseguono la configurazione una tantum: queste istruzioni vengono eseguite dall'alto verso il basso la prima volta che il modulo viene importato da qualche parte, impostando le relative variabili e funzioni. Un modulo Python può essere eseguito direttamente, come sopra python3 hello.py Bob, oppure può essere importato e utilizzato da un altro modulo. Quando un file Python viene eseguito direttamente, la variabile speciale "__name__" viene impostata su "__main__". Pertanto, è comune che il boilerplate if __name__ ==... mostrato sopra chiami una funzione main() quando il modulo viene eseguito direttamente, ma non quando viene importato da qualche altro modulo.

In un programma Python standard, l'elenco sys.argv contiene gli argomenti della riga di comando nel modo standard in cui sys.argv[0] è il programma stesso, sys.argv[1] è il primo argomento e così via. Se conosci argc, o il numero di argomenti, puoi semplicemente richiedere questo valore da Python con len(sys.argv), proprio come abbiamo fatto nel codice dell'interprete interattivo sopra riportato quando richiedi la lunghezza di una stringa. In generale, len() può indicare la lunghezza di una stringa, il numero di elementi negli elenchi e nelle tuple (un'altra struttura di dati simile a un array) e il numero di coppie chiave-valore in un dizionario.

Funzioni definite dall'utente

Le funzioni in Python sono definite come segue:

# Defines a "repeat" function that takes 2 arguments.
def repeat(s, exclaim):
    """
    Returns the string 's' repeated 3 times.
    If exclaim is true, add exclamation marks.
    """

    result = s + s + s # can also use "s * 3" which is faster (Why?)
    if exclaim:
        result = result + '!!!'
    return result

Notare anche come le righe che compongono la funzione o l'istruzione if siano raggruppate in base allo stesso livello di rientro. Abbiamo presentato anche 2 diversi modi per ripetere le stringhe, utilizzando l'operatore + che è più facile da usare, ma * funziona anche perché è l'operatore "repeat" di Python, il che significa che '-' * 10 offre a '----------', un modo perfetto per creare una "riga" sullo schermo. Nel commento del codice, abbiamo accennato al fatto che * funziona più velocemente di +, perché * calcola le dimensioni dell'oggetto risultante una volta, mentre con + questo calcolo viene eseguito ogni volta che viene chiamato +. Sia + che * sono chiamati operatori "sovracaricati" perché hanno significati diversi per i numeri rispetto alle stringhe (e ad altri tipi di dati).

La parola chiave def definisce la funzione con i relativi parametri tra parentesi e il codice rientrato. La prima riga di una funzione può essere una stringa di documentazione ("docstring") che descrive la funzione. Il docstring può essere costituito da una singola riga o una descrizione su più righe, come nell'esempio sopra. (Sì, si tratta di "Virgolette triple", una funzionalità unica di Python). Le variabili definite nella funzione sono locali a quella funzione, pertanto "risultato" nella funzione precedente è separato da una variabile "risultato" in un'altra funzione. L'istruzione return può accettare un argomento, che in questo caso è il valore restituito al chiamante.

Di seguito è riportato il codice che chiama la funzione repeat() riportata sopra e stampa il valore restituito:

def main():
    print(repeat('Yay', False))      ## YayYayYay
    print(repeat('Woo Hoo', True))   ## Woo HooWoo HooWoo Hoo!!!

In fase di esecuzione, le funzioni devono essere definite dall'esecuzione di "def" prima di essere chiamate. È normale definire una funzione main() nella parte inferiore del file con le funzioni che chiama sopra.

Rientro

Una caratteristica insolita di Python è che il rientro degli spazi di un frammento di codice ne influisce sul significato. Un blocco logico di istruzioni, come quelle che compongono una funzione, deve avere tutte la stessa rientratura, impostata in base alla rientratura della funzione principale o di "if" o di qualsiasi altro comando. Se una delle righe di un gruppo ha un rientro diverso, viene segnalata come errore di sintassi.

L'utilizzo degli spazi in Python può sembrare un po' strano all'inizio, ma è logico e mi sono abituato molto rapidamente. Evita di usare le schede, perché complicano notevolmente lo schema di rientro (per non parlare delle TAB possono avere significati diversi su piattaforme diverse). Imposta l'editor in modo che inserisca spazi anziché TAB per il codice Python.

Una domanda frequente che i principianti si fanno è: "Quanti spazi devo far rientrare?". Secondo la guida ufficiale allo stile di Python (PEP 8), devi rientrare con 4 spazi. (Curiosità: le linee guida di stile interne di Google prevedono un rientro di 2 spazi!)

Codice controllato in fase di runtime

Python esegue pochissimi controlli in fase di compilazione, rimandando quasi tutti i controlli di tipo, nome e così via su ogni riga fino all'esecuzione della riga. Supponiamo che la funzione main() sopra indicata chiami repeat() come segue:

def main():
    if name == 'Guido':
        print(repeeeet(name) + '!!!')
    else:
        print(repeat(name))

L'istruzione if contiene un errore evidente, in cui la funzione repeat() è stata digitata per errore come repeeeet(). La cosa divertente in Python è che questo codice viene compilato ed eseguito correttamente a condizione che il nome in fase di esecuzione non sia "Guido". Solo quando un'esecuzione tenta effettivamente di eseguire repeeeet(), viene rilevato che non esiste questa funzione e viene generato un errore. In questo snippet è presente anche un secondo errore. A name non è stato assegnato un valore prima del confronto con "Guido". Python solleva un "NameError" se provi a valutare una variabile non assegnata. Questi sono alcuni esempi che dimostrano che, quando esegui per la prima volta un programma Python, alcuni dei primi errori che visualizzi saranno semplici errori ortografici o variabili non inizializzate come queste. Questo è un campo in cui i linguaggi con un sistema di tipi più dettagliato, come Java, hanno un vantaggio: possono rilevare questi errori in fase di compilazione (ma ovviamente devi gestire tutte le informazioni sui tipi, quindi è un compromesso).

Python 3 ha introdotto i suggerimenti di tipo. I suggerimenti di tipo ti consentono di indicare il tipo di ciascun argomento di una funzione, nonché il tipo dell'oggetto restituito dalla funzione. Ad esempio, nella funzione annotata def is_positive(n: int) -> bool:, l'argomento n è un int e il valore restituito è bool. Più avanti spiegheremo il significato di questi tipi. I suggerimenti di tipo sono però del tutto facoltativi. Vedrai sempre più codice che adotta i suggerimenti di tipo perché, se li utilizzi, alcuni editor come cider-v e VS.code possono eseguire controlli per verificare che le funzioni vengano chiamate con i tipi di argomenti corretti. Possono anche suggerire e convalidare gli argomenti durante la modifica del codice. Questo tutorial non tratterà i suggerimenti relativi ai tipi, ma vogliamo assicurarci che tu ne sia a conoscenza se ne hai sentito parlare o li vedi in natura.

Nomi delle variabili

Poiché le variabili Python non hanno un tipo specificato nel codice sorgente, è molto utile assegnare nomi significativi alle variabili per ricordare cosa sta succedendo. Quindi utilizza "name" se è un singolo nome, "names" se è un elenco di nomi e "tuple" se è un elenco di tuple. Molti errori di Python di base derivano dal dimenticare il tipo di valore presente in ogni variabile, quindi utilizza i nomi delle variabili (l'unico strumento a tua disposizione) per tenere tutto in ordine.

Per quanto riguarda la denominazione effettiva, alcune lingue preferiscono underscored_parts per i nomi delle variabili composti da "più di una parola", mentre altre preferiscono camelCasing. In generale, Python preferisce il metodo del trattino basso, ma guida gli sviluppatori a concentrarsi su camelCasing se si integra nel codice Python esistente che già utilizza questo stile. La leggibilità conta. Scopri di più nella sezione sulle convenzioni di denominazione in PEP 8.

Come puoi immaginare, parole chiave come "if" e "while" non possono essere utilizzate come nomi di variabili, altrimenti verrà generato un errore di sintassi. Tuttavia, fai attenzione a non utilizzare i comandi incorporati come nomi di variabili. Ad esempio, anche se "str", "list" e "print" possono sembrare buoni nomi, devi sostituire queste variabili di sistema. I comandi incorporati non sono parole chiave e, pertanto, sono suscettibili di essere utilizzati inavvertitamente dai nuovi sviluppatori Python.

Scopri di più sui moduli e sui relativi spazi dei nomi

Supponiamo che tu abbia un modulo "binky.py" che contiene "def foo()". Il nome completo della funzione foo è "binky.foo". In questo modo, i vari moduli Python possono assegnare i nomi che preferiscono alle funzioni e alle variabili e i nomi delle variabili non entrano in conflitto: module1.foo è diverso da module2.foo. Nel vocabolario di Python, diremmo che binky, module1 e module2 hanno ciascuno i propri "spazi dei nomi", che, come puoi immaginare, sono associazioni di nomi di variabili a oggetti.

Ad esempio, il modulo "sys" standard contiene alcune strutture di sistema standard, come l'elenco argv e la funzione exit(). Con l'istruzione "import sys" puoi accedere alle definizioni nel modulo sys e renderle disponibili con il nome completo, ad esempio sys.exit(). (Sì, anche "sys" ha uno spazio dei nomi).

  import sys

  # Now can refer to sys.xxx facilities
  sys.exit(0)

Esiste un altro modulo di importazione che ha il seguente aspetto: "from sys import argv, exit". Ciò rende argv e exit() disponibili con i loro nomi brevi; tuttavia, consigliamo di utilizzare il formato originale con nomi completi perché è molto più facile determinare da dove proviene una funzione o un attributo.

Esistono molti moduli e pacchetti che sono inclusi in un'installazione standard dell'interprete Python, quindi non devi fare altro per utilizzarli. Questi sono noti collettivamente come "libreria standard di Python". I moduli/pacchetti più utilizzati includono:

  • sys: accesso a exit(), argv, stdin, stdout e così via.
  • re: espressioni regolari
  • os: interfaccia del sistema operativo, file system

Puoi trovare la documentazione di tutti i moduli e i pacchetti della libreria standard all'indirizzo http://docs.python.org/library.

Guida in linea, help() e dir()

Esistono diversi modi per ricevere assistenza per Python.

  • Esegui una ricerca su Google, iniziando con la parola "python", ad esempio "lista python" o "stringa python minuscola". Spesso la risposta è la prima che appare. Per qualche motivo, questa tecnica sembra funzionare meglio per Python che per altri linguaggi.
  • Il sito ufficiale di documenti Python (docs.python.org) offre documenti di alta qualità. Tuttavia, spesso trovo che una ricerca su Google di un paio di parole sia più veloce.
  • È disponibile anche una mailing list ufficiale per Tutor progettata appositamente per i nuovi utenti di Python e/o della programmazione.
  • Su StackOverflow e Quora puoi trovare molte domande (e risposte).
  • Utilizza le funzioni help() e dir() (vedi di seguito).

All'interno dell'interprete Python, la funzione help() recupera le stringhe di documentazione per vari moduli, funzioni e metodi. Queste stringhe di documenti sono simili a javadoc di Java. La funzione dir() indica quali sono gli attributi di un oggetto. Di seguito sono riportati alcuni modi per chiamare help() e dir() dall'interprete:

  • help(len): stringa di aiuto per la funzione len() integrata; tieni presente che si tratta di "len" e non di "len()", che è una chiamata alla funzione, che non è richiesta
  • help(sys): stringa di aiuto per il modulo sys (deve eseguire prima un import sys)
  • dir(sys): dir() è simile a help() ma fornisce solo un breve elenco dei simboli definiti, o "attributi"
  • help(sys.exit): stringa di guida per la funzione exit() nel modulo sys
  • help('xyz'.split): stringa di guida per il metodo split() per gli oggetti stringa. Puoi chiamare help() con l'oggetto stesso o con un esempio dell'oggetto, oltre al relativo attributo. Ad esempio, chiamare help('xyz'.split) è come chiamare help(str.split).
  • help(list): stringa di guida per gli oggetti list
  • dir(list): mostra gli attributi dell'oggetto list, inclusi i relativi metodi
  • help(list.append): stringa di guida per il metodo append() per gli oggetti list