Skip to content

Instantly share code, notes, and snippets.

@ricpol
Last active October 28, 2024 12:48
Show Gist options
  • Save ricpol/2ca0ae46f02bfddf08036fa85519aa97 to your computer and use it in GitHub Desktop.
Save ricpol/2ca0ae46f02bfddf08036fa85519aa97 to your computer and use it in GitHub Desktop.
Come installare e usare Python su Windows

**NOTA IMPORTANTE Questi appunti sono ormai molto datati e incompleti. Li lascio qui per ragioni storiche e affettive, ma davvero, non prendeli alla lettera e non sorprendetevi se ci sono cose sbagliate. Il mio libro Python in Windows parla di tutte queste cose, e di molto altro ancora, in modo più aggiornato, completo e corretto. Vi suggerisco almeno di scaricare il capitolo introduttivo gratuito per farvi un'idea degli argomenti trattati. **

Come installare e usare Python su Windows.

Questi appunti descrivono come installare Python su Windows in modo da creare un ambiente di lavoro sano, facile da usare all'inizio e che possa durare nel tempo senza sfuggirvi di mano quando le cose si fanno più complicate.

Per prima cosa, chiariamo: installare Python su Windows non è per niente complicato di per sé. Potete andare sul sito, scaricare, installare in pochi secondi e cominciare subito a lavorare. All'inizio non avrete difficoltà. Quando prima o poi verranno a galla i problemi, poco male: in casi estremi, potete disinstallare tutto e ricominciare daccapo in modo più accorto.

Ma se invece volete partire subito col piede giusto, questi appunti sono qui per voi. Non bisogna per forza seguire questi consigli: ma se non sapete come orientarvi, allora fidatevi.

Indice.

  • Prerequisiti.
  • Parte prima: installazione.
    • Quale versione di Python?
    • Installare Python 3.6.
    • Installare Python 2.7.
    • Scegliere se avviare Python 2 oppure Python 3.
    • Installazione di default.
    • Eseguire uno script Python.
    • Specificare una versione di default anche per il launcher py.
    • Eseguire uno script con il doppio clic.
    • Associare i file .py all'editor, invece.
    • I file .pyw.
    • I file .pyc.
    • I file .pyz.
    • Riassunto: che cosa vi conviene fare, in breve.
    • Riassunto: come funziona py (e-python) in breve.
  • Parte seconda: virtual environment.
    • Che cosa è un virtual environment.
    • Dove mettere i virtual environment.
    • Creare e usare un virtual environment di Python 3.6.
    • Creare un virtual environment di Python 2.7.
    • Eseguire script nei virtual environment.
    • Riassunto: come funziona py (e-python), con e senza i venv.
  • Parte terza: installare pacchetti esterni con Pip.
    • PyPI: la repository ufficiale delle librerie Python.
    • Pip: il package manager ufficiale di Python.
    • Liste di "requirements".
    • Installare pacchetti locali.
    • Wheel e pacchetti binari precompilati.
    • Pacchetti ausiliari di uso comune.
    • Riassunto: installare pacchetti.
    • Che cosa non sono i venv.
  • Parte quarta: intestazioni nei file.
    • La shebang: dichiarare che lo script deve essere eseguito da Python.
    • Riassunto: come usare le shebang?
    • Le dichiarazioni di encoding.
  • Parte quinta: struttura di un progetto Python.
    • Il meccanismo degli import in Python.
    • Come gestire il proprio codice Python.
    • Struttura di un progetto Python.
    • Numeri di versione.
    • Manuale di stile e controllo automatico dello stile.
  • Parte sesta: avviare con il doppio clic.
    • Il problema con il doppio clic.
    • Il problema con i batch file.
    • Impostare la directory corrente con Python.
    • Se lo script ha bisogno di un venv.
    • Che cosa fare con l'output dello script.
    • Che cosa fare in caso di errore.
  • Parte settima: tool per programmare.
    • ConEmu: console emulator.
    • Git: version control system.
    • Jupyter Notebook: shell interattiva.
    • Scegliere un editor.
    • Font per programmatori.
    • Librerie Python che potrebbero essere utili in Windows.
    • Distribuzioni alternative di Python.
    • Implementazioni alternative di Python.
  • Parte ottava: Python, Windows e Unicode.
    • Unicode nella shell.
    • Unicode nei nomi dei file.
    • Abilitare i nomi lunghi dei file.
    • Unicode nei file.
  • Link di riferimento.

Prerequisiti.

Ecco una lista di prerequisiti per voi e il vostro computer. Niente di particolarmente complicato:

  1. Dovreste avere una versione di Windows non preistorica: diciamo, dalla 7 in poi. Potete installare Python anche su Windows più antichi, ma le cose si fanno più difficili: le versioni di Python recenti non sono più compatibili, quelle più vecchie non sono più supportate, potrebbero volerci accorgimenti particolari... Insomma, un groviglio di situazioni complicate. Tecnicamente, la regola è scritta nella Pep 11. Per orientarvi, considerate che Python 3.7 supporta ancora Vista, ma non oltre. L'ultima versione a supportare XP è la 3.4.
  2. Dovreste avere una versione di Windows aggiornata. Gli aggiornamenti automatici sono noiosi e molti li disabilitano. Ma potrebbero essere necessari per le ultime versioni di Python. In particolare, Python 3.5/3.7 richiedono i runtime C++ di Visual Studio 2015. Fate caso alla data: se avete un Windows vecchiotto (7 o 8) e da qualche anno avete bloccato gli aggiornamenti automatici, allora forse Python non si installerà. In questo caso, non c'è molto da fare. Ri-abilitate gli aggiornamenti automatici (almeno temporaneamente!) e dedicate una mattinata a mettervi in pari.
  3. Sarebbe meglio avere un processore (e quindi un Windows) a 64 bit. Esistono ancora le versioni di Python a 32 bit, ed è possibile installarle: tutto funzionerà lo stesso. Tuttavia è possibile che in futuro vi troverete a installare librerie aggiuntive che hanno solo la versione a 64 bit. In generale, l'architettura a 32 bit (x86) è in disarmo. Vi conviene davvero comprarvi un computer più recente.
  4. Il vostro computer dovrebbe essere vostro. Ovvero, dovreste avere accesso come amministratore. È possibile installare Python anche come utente non privilegiato, per esempio su una workstation aziendale. Ma allora i privilegi del vostro account potrebbero non essere sufficienti. La casistica è troppo ampia per essere affrontata qui. Vi conviene tentare: se non ci riuscite, vuol dire che non avete i permessi sufficienti per installare Python, e dovreste rivolgervi a un amministratore.
  5. Dovreste saper usare la shell. Almeno quel poco che basta. Questo non è proprio evitabile: Python si manovra dalla shell. La shell di Windows è cmd.exe (la "dos-box" nera, per intenderci). È una pessima shell in confronto alle opzioni disponibili su Linux. Ma poco male: non è obbligatorio usarla come un hacker Linux, per lavorare con Python. Come minimo dovete saperla aprire, muovervi tra le directory, avere la nozione di "directory corrente". Ovviamente, più ne sapete (creare/eliminare file e directory, etc.), meglio è. Se non sapete proprio nulla, cercate in rete (per esempio questa guida).
  6. Dovreste sapere che cosa sono e come si impostano le variabili d'ambiente, e in particolare che cos'è e a cosa serve la path di sistema.
  7. Python non dovrebbe essere già installato nel vostro sistema. Questa guida parte da zero, perché su Windows di solito è così. Non trovate Python pre-installato, come su Linux. Bisogna avercelo messo apposta, per trovarlo. Se il computer è vostro, dovreste saperlo. Se siete in dubbio, potete verificarlo. Prima di tutto aprite una shell è provate uno di questi comandi: python, oppure anche py. Se ottenete solo degli errori va bene, ma non è ancora detto. Verificate che non compaia nell'elenco dei programmi installati (dal Pannello di Controllo). Eventualmente, disinstallate quello che trovate.
  8. Un dettaglio importante: Windows dovrebbe farvi vedere il nome completo dei file. Windows nasconde l'estensione perché così è più comodo per gli utenti "normali". Ma voi non siete utenti normali. Fate in modo che Windows vi mostri sempre l'estensione: come sicuramente già sapete, potete impostare le "Opzioni Cartella" per questo.
  9. Ancora un dettaglio: Windows dovrebbe farvi vedere tutti i file, compresi quelli nascosti. Anche in questo caso, le "Opzioni Cartella" possono essere impostate di conseguenza.

Parte prima: installazione.

Quale versione di Python?

Come forse sapete, qualche anno fa Python si è evoluto in una nuova versione (Python 3) incompatibile con quella precedente (Python 2). Dal punto di vista dell'apprendimento, le due versioni sono pressoché uguali: se imparate Python 3, basta poco per imparare anche Python 2, e viceversa. Ma tecnicamente le due versioni sono incompatibili, e ci sono voluti anni di lavoro (e recriminazioni) perché Python 3 fosse adottato dalla comunità degli sviluppatori.

Oggi il processo di migrazione verso Python 3 è compiuto. La quasi totalità delle librerie importanti è disponibile anche per Python 3, e nessuno produce più cose nuove per Python 2. Tuttavia Python 2 resta ancora molto adottato soprattutto perché una gran quantità di "programmi" (ovvero, non librerie) è ancora scritta in Python 2, e sarebbe troppo costoso migrare. Python 2 è una versione "legacy": è ancora supportata dagli sviluppatori e riceve aggiornamenti di sicurezza e bugfix. Tuttavia, lo sviluppo di nuove feature nel linguaggio avviene ormai solo più su Python 3. Tra qualche anno, Python 2 sarà dichiarato ufficialmente non supportato e abbandonato.

Di conseguenza, la scelta in realtà è piuttosto ovvia. Se iniziate a programmare con Python, dovreste installare Python 3. Usate Python 2 solo se ne avete bisogno: ovvero, se lavorate in un team che usa Python 2, oppure se avete bisogno di librerie o programmi che non sono mai stati aggiornati a Python 3.

Più nello specifico, quale versione utilizzare? Le versioni di Python sono numerate secondo il classico schema a tre numeri: un numero di versione maggiore (2 o 3, incompatibili tra loro), seguito da un numero di versione minore, seguito da un numero di versione di bugfix. Le versioni minori sono tra loro compatibili in linea di massima, anche se versioni successive possono introdurre delle nuove feature.

Se usate Python 2, in pratica non avete scelta: dovete installare la versione 2.7, la più recente. Installare la 2.6 è ormai una rarità per specialisti (si fa solo se ce n'è assolutamente bisogno). Le versioni ancora precedenti sono obsolete. All'epoca in cui sono scritti questi appunti, l'ultima release della serie 2.7 è la versione 2.7.15: in ogni caso, dovreste installare la più recente tra quelle disponibili.

Se usate (come probabile) Python 3, allora la versione più recente all'epoca di questi appunti è la 3.7.0, e vi conviene installare quella (o una più recente della serie 3.7, man mano che usciranno). Va bene anche installare la versione più recente della serie 3.6, o persino anche la 3.5 se vi serve. Le serie precedenti, invece, sono sconsigliate: la 3.4 funziona, ma manca di alcuni elementi importanti proprio in ambiente Windows: se la usate, allora questi appunti non sono validi qua e là. Le versioni ancora precedenti (dalla 3.0 alla 3.3) non sono più supportate.

Ed eccoci al bello: non dovete per forza scegliere, è possibile installare e utilizzare più versioni di Python contemporaneamente. Non occorre farlo: tuttavia è possibile e anche facile. In questi appunti, a titolo di esempio, installeremo e impareremo a usare le versioni 3.7.0 e 2.7.15. Tuttavia è possibile anche installare più di due versioni, magari più versioni di Python 3 (per esempio, la 3.6 e la 3.7 insieme)... o anche, naturalmente, scegliere e installare una sola versione e accontentarsi di quella.

Una raccomandazione: anche se per il momento decidete di installare una sola versione di Python, seguite ugualmente tutte le raccomandazioni che seguono, come se doveste utilizzare due versioni insieme. Sarà più facile aggiungere una seconda versione in seguito, nel caso.

Installare Python 3.7.

Per prima cosa, installiamo Python 3 (ma potete cominciare anche con Python 2, se preferite). La serie più aggiornata al momento disponibile è la 3.7, e per la precisione la versione 3.7.0. Andiamo sul sito di Python e diamo un'occhiata alla lista degli installer disponibili. Ci sono molte opzioni, ma noi vogliamo il "Windows x86-64 executable installer". Scarichiamo l'eseguibile e... lo eseguiamo, naturalmente.

Nella prima schermata, invece di cliccare sull'allettante "Install now", scegliamo "Customize installation" e verifichiamo nel dettaglio le varie possibilità. In pratica ci interessano tutte le opzioni: l'unica voce che, volendo, possiamo tralasciare è "Python Test Suite". Tutte le altre devono essere selezionate. Nella schermata successiva, possiamo tralasciare solo le due voci relative alle opzioni di debug. È fondamentale in particolare selezionare "Add Python to environment variables".

Una considerazione particolare merita la voce "Install for all users". Se avete i permessi necessari (siete amministratori) vi conviene selezionarla. Altrimenti, non vi resta che installare solo nel vostro user-space, se il vostro account gode almeno di questo privilegio. Notate che Python verrà installato in C:/Program Files/Python37 se lo installate "for all user"; se lo installate solo per voi stessi, finirà invece in C:/Users/<VOSTRO_NOME>/AppData/Local/Programs/Python/Python37.

Se avete la possibilità di installare "for all users", allora naturalmente (nella schermata precedente) vi conviene installare "for all users" anche il "py launcher" (vedremo poi di cosa si tratta).

Concluse queste scelte, non resta che installare. Al termine, possiamo verificare se Python è stato effettivamente installato in modo corretto: apriamo una shell, e avviamo l'eseguibile di Python. Siccome durante l'installazione abbiamo specificato che Python deve essere inserito nella path di sistema, basterà inserire python e premere invio: dovrebbe apparire la shell di Python, più o meno così:

> python
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Alcune osservazioni. Primo, il prompt della shell > è il prompt generico di Windows (l'equivalente di $ in Linux). In questi appunti significa "qualsiasi directory di lavoro va bene": nell'esempio qui sopra, potreste avere un prompt come C:\>, o qualsiasi altro: siccome Python è nella path di sistema, Windows è in grado di trovare l'eseguibile python.exe da qualunque directory di lavoro in cui vi trovate. Notate che il prompt della shell > non va confuso con il prompt dell'interprete interattivo dei comandi Python >>> (il fatto che l'interprete interattivo dei comandi Python si chiami per brevità "shell di Python" contribuisce alla confusione!). Secondo, tra le informazioni mostrate nell'intestazione della shell di Python, non lasciatevi ingannare da quel on win32: Python non crede che il vostro sistema è a 32 bit. Per Python, win32 vuole dire Windows in generale. Terzo, per uscire dalla shell di Python e tornare al prompt normale, basta inserire exit() e premere invio.

Una volta verificato che il comando python funziona, per sicurezza verificate che funzioni anche il più semplice py (anche questo eseguibile dovrebbe essere nella path di sistema. Vedremo tra poco esattamente che ruolo ha). Per il momento, il risultato dovrebbe essere lo stesso.

Installare Python 2.7.

Adesso possiamo installare anche Python 2.7 (al momento di scrivere questi appunti, la versione 2.7.13 è la più recente: controllate di avere sempre la più aggiornata). Come prima, guardiamo la lista degli installer disponibili e scegliamo il "Windows x86-64 MSI installer", scarichiamolo ed eseguiamolo.

Questa volta vediamo subito che l'installer è un vecchio MSI, molto più spartano di quello "all'ultima moda" della serie 3.6/3.7. Ma poco importa, le opzioni sono molto simili. Se possibile, installiamo "for all users". Notiamo che questa volta la directory proposta è banalmente C:/Python27, in tutti i casi. Questo è un triste retaggio del passato: fino alla versione 3.5, Python si installava direttamente in C:/, pratica naturalmente sconsigliabile in Windows, e perfino un potenziale rischio per la sicurezza. Ma pazienza, ormai la convenzione è troppo radicata per poterla cambiare.

Per quanto riguarda le altre opzioni, in generale devono essere tutte selezionate. Accertatevi che "Add python.exe to Path" sia selezionata. Come sopra, potete trascurare "Test suite". L'unica complicazione notevole riguarda "Register extension": questa voce dovrebbe essere

  • inclusa, se avete intenzione di installare solo Python 2;
  • esclusa, se avete intenzione di installare anche Python 3 (e in particolare una versione superiore alla 3.3). Nel nostro caso, dunque, la escluderemo. Vedremo che è sempre possibile registrare le associazioni manualmente in seguito, se necessario.

Terminata l'installazione, verifichiamo che tutto sia a posto. Questa volta il comando necessario nella shell è py -2 (spiegheremo meglio tutto tra pochissimo):

> py -2
Python 2.7.15 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Anche in questo caso, per uscire da Python potete inserire exit().

Scegliere se avviare Python 2 oppure Python 3.

Adesso che avete due versioni di Python installate, occorre trovare il modo di avviare l'una o l'altra, a scelta. Per fortuna questo è semplicissimo.

Se avete installato Python 3 (almeno dalla 3.3 in poi), avete a disposizione un apposito "launcher" py.exe che serve appunto a gestire più versioni di Python contemporaneamente. Il launcher non è disponibile per le versioni precedenti di Python. In particolare, se avete installato solo la 2.7, di sicuro non avete il launcher: del resto, in questo caso non ne avete bisogno: per avviare l'unico Python di cui disponete, vi basterà un python dalla shell.

Il launcher vi consente di avviare rapidamente la versione di Python che preferite: usate py -2 per avviare Python 2, e py -3 per Python 3. Un py senza ulteriori specificazioni, d'altra parte, avvia la versione più recente (nel nostro caso, la 3.7).

Il launcher funziona allo stesso modo anche per versioni diverse di Python 3 (o di Python 2, per quel che vale). Per esempio, supponiamo che abbiate installate contemporaneamente le versioni 2.7, 3.6 e 3.7: allora potete selezionarle con py -2, py -3.6 e py -3.7 rispettivamente. Inoltre, py -3 da solo avvierà la versione più recente di Python 3 (in questo caso la 3.7).

Naturalmente, se avete una sola versione di Python installata, allora py (o python) avvieranno sempre e solo quella.

Installazione di default.

Che cosa succede quando, invece di usare il launcher py, invocate direttamente l'eseguibile di Python, ovvero python, dalla shell? Questo è poco importante al momento perché in pratica, da quando esiste il launcher, vi conviene usare quello. L'unico caso in cui py non è disponibile è quando avete solo Python 2 installato: allora userete python per avviare l'unico Python che avete a disposizione. Vedremo più tardi che le cose si complicano leggermente quando entrano in gioco i virtual environments.

Invocare python dalla shell avvia la "versione di default" di Python. Che cos'è la "versione di default"? Chiaramente, se avete una sola versione installata, non può essere che quella. Se ne avete più di una, allora è la prima che Windows trova nella path di sistema.

Questo può essere un po' complicato. Se installate una versione di Python senza l'opzione di includerla nella path di sistema, allora ovviamente Windows non ha modo di conoscere l'indirizzo esatto dell'eseguibile python.exe, e quindi un python dalla shell non basterà a trovare quella versione (per avviarla, dovete specificare l'indirizzo completo, per esempio C:/Program Files/Python35/python.exe o qualcosa del genere). Se invece al momento dell'installazione specificate che l'eseguibile deve essere incluso nella path di sistema, allora un semplice python troverà l'eseguibile. Ma se più installazioni sono nella path di sistema, allora python si fermerà alla prima che trova nell'ordine, e avvierà quella. Siccome l'installer di Python inserisce la sua versione in testa alla path di sistema, in pratica la prima versione che Windows trova è l'ultima che avete installato in ordine di tempo. Ma questo può essere ancora complicato dal fatto se avete installato delle versioni "for all users" o solo nel vostro user space, e se ci sono contemporaneamente presenti versioni "per tutti" e versioni "solo per voi".

In pratica, è raccomandabile installare tutte le versioni di Python "for all users", oppure tutte "solo per voi"; inoltre, è meglio inserirle comunque tutte nella path di sistema. Se in futuro doveste disinstallare una versione, siete sicuri che comunque le altre sono già nella path, e quindi python continuerà a funzionare in qualche modo (trovando un'altra versione).

In ogni caso, per essere sicuri di quale versione corrisponde il python di default sulla vostra macchina, basta... fare la prova! Fate comunque attenzione: quello che vale per voi potrebbe non valere su un'altra macchina. In generale, non potete essere sicuri che uno script Python che per voi funziona, continuerà a funzionare allo stesso modo ovunque: dipende da quali versioni di Python sono installate sulle altre macchine, e magari in quale ordine. La necessità di virtual environment complica ulteriormente le cose, come vedremo. In generale questo è un problema di pacchettizzazione e distribuzione del software Python, ed è troppo complesso per essere affrontato in questa guida. Torneremo comunque sull'argomento per alcune indicazioni di base.

Eseguire uno script Python.

Un conto è invocare la shell interattiva di Python, ma noi vogliamo anche poter eseguire uno script. Se avete diverse installazioni di Python compresenti, è importante sapere quale Python sta eseguendo il vostro script.

Per prima cosa dobbiamo creare un piccolo script di prova: aprite un nuovo file e chiamatelo test.py (attenzione all'estensione! Ricordate, dovete impostare Windows perché vi mostri sempre il nome completo dei file, estensione compresa). Potete metterlo dovunque, per il momento. Per evitare di scrivere troppo nella shell, è meglio fare in modo che abbia un indirizzo breve: per esempio, C:/test/test.py. Dentro il file scrivete solo queste poche righe:

import sys

print('sono eseguito da: ' + sys.executable)

Una nota per chi proprio non ha mai fatto queste cose: si dà per scontato che i programmi non si scrivono in Word! Dovete usare un editor di testo per questo. Ci sono molti editor "da programmatori", e discuteremo alcune scelte possibili. Per il momento, se non avete altro, va benissimo anche solo il Blocco Note (ma solo per il momento, beninteso).

A dire il vero, gli esempi che dobbiamo scrivere sono talmente brevi che forse vi conviene scrivere direttamente il file dalla shell, con il comando copy, senza passare da un editor:

> cd c:/test
C:\test > copy con test.py
import sys
print('sono eseguito da: ' + sys.executable)
<CTRL+Z><INVIO>

Anche se non sapete programmare in Python, il significato di queste due righe è abbastanza chiaro: questo script semplicemente scrive nella shell l'indirizzo dell'interprete Python che lo sta eseguendo. Abbiamo scelto delle istruzioni che sono legali sia in Python 2 sia in Python 3, quindi potete eseguire lo script con qualsiasi versione di Python che avete installata.

Per eseguire uno script, semplicemente invocate l'interprete Python (preferibilmente attraverso il launcher) seguito dal nome dello script (o dal suo indirizzo per intero, se siete in una diversa directory di lavoro):

Facciamo qualche prova:

> cd c:/test
C:\test> py -2 test.py
sono eseguito da: C:\Python27\python.exe
C:\test> py -3 test.py
sono eseguito da: C:\Program Files\Python37\python.exe
C:\test> py test.py
sono eseguito da: C:\Program Files\Python37\python.exe
C:\test> python test.py
sono eseguito da: C:\Python27\python.exe

Se avete seguito fin qui, niente di tutto questo dovrebbe sorprendervi. Il launcher py con la versione specificata (py -2 o py -3) esegue lo script con la versione che avete indicato. Il launcher py senza nessuna specificazione utilizza la versione più recente. Infine, python usa la versione di default.

Specificare una versione di default anche per il launcher py.

Se lo invocate senza specificare nulla, allora il launcher userà la versione più recente tra quelle installate. Potete però definire una versione preferenziale per il launcher py, se volete. Per fare questo, dovete impostare la variabile d'ambiente PY_PYTHON.

Ecco come funziona:

C:\test> set PY_PYTHON=3
C:\test> py test.py
sono eseguito da: C:\Program Files\Python37\python.exe
C:\test> set PY_PYTHON=2
C:\test> py test.py
sono eseguito da: C:\Python27\python.exe

E d'altra parte:

> set PY_PYTHON=3
> py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
> set PY_PYTHON=2
> py
Python 2.7.15 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()

Ci vuole un breve promemoria sulle variabili d'ambiente, a questo punto. Ricordiamo che il comando di shell set imposta una variabile d'ambiente solo nello spazio della shell corrente. In un'altra shell aperta contemporaneamente, la variabile non è visibile; e se chiudete la shell, la variabile sparisce. Per impostare una variabile d'ambiente in modo "definitivo" potete usare setx in una shell "privilegiata", oppure naturalmente potete procedere dalle impostazioni di sistema. Potete esaminare il valore attuale di una variabile con un semplice echo, per esempio echo %PY_PYTHON%, oppure echo %PATH% etc.

Torniamo a Python. Come vedete, un py generico invoca la versione dettata da PY_PYTHON, se impostata, altrimenti la più recente. Non dovrebbe comunque mai essere necessario ricorrere a PY_PYTHON: come vedremo, gli script dovrebbero avere una "shebang", ma in definitiva basta specificare la versione al momento di eseguire lo script con py.

Eseguire uno script con il doppio clic.

Questo non si dovrebbe mai fare, davvero. In Windows viene naturale "fare doppio clic" su qualcosa, ma gli script Python si dovrebbero avviare dalla shell. Solo in questo modo è possibile raccogliere l'output e gli eventuali messaggi d'errore, impostare la directory di lavoro ed eventuali variabili d'ambiente, e in definitiva capire quello che si sta facendo. Quindi abituatevi a tenere una shell aperta e a invocare i vostri script da quella. A maggior ragione, vedremo che l'uso dei virtual environment in pratica esclude la possibilità di usare il doppio clic.

Naturalmente gli utenti finali dei vostri programmi, in futuro, dovranno avere un entry point comodo da usare: qualcosa su cui "fare doppio clic". Questo è possibile, ma è un aspetto di un problema completamente differente, quello della pacchettizzazione e distribuzione dei programmi Python. Per il momento, invece, ci occupiamo dell'ambiente di lavoro del programmatore.

Detto che voi dovreste usare la shell, è utile comunque sapere che cosa succede quando fate doppio clic sul file di uno script Python. Qui entrano in gioco le associazioni che Windows fa tra estensioni e programmi predefiniti (il meccanismo per cui quando fate doppio clic su un file .doc si apre Word). È importante far sapere a Windows che il programma predefinito per i file con estensione .py deve essere il launcher py, e non direttamente l'interprete python.exe.

È molto semplice verificarlo: se l'icona del file .py ha il disegno di un razzo stilizzato in overlay, allora il programma predefinito è il launcher.

Potrebbe succedere che i file .py non siano associati con il launcher? Purtroppo sì. Quando installate una versione di Python, i file .py possono venire associati al launcher solo se... esiste il launcher, naturalmente! Il launcher esiste solo dalla versione 3.3 in poi. Questo significa che, se installate una versione più vecchia, i file .py vengono associati direttamente all'interprete Python, "alla vecchia maniera".

Ma c'è di peggio. Se installate una versione recente (che ha il launcher) e successivamente una versione più vecchia (che non ce l'ha) quest'ultima potrebbe sovrascrivere le associazioni già impostate dalla prima. Dovete stare attenti, in questi casi, a de-selezionare l'opzione "Register extensions" in fase di installazione (ricordate? Ne avevamo parlato sopra).

In ogni caso, se vi ritrovate con le associazioni sbagliate, potete sempre correggere nel solito modo: fate clic col pulsante destro sul vostro modulo test.py, scegliete "Apri con...", e cambiate programma predefinito: eventualmente dovete "sfogliare" fino a individuare il launcher py.exe (che, se avete installato "for all users", è in C:/windows/py.exe).

Se i file .py sono correttamente associati al launcher, allora fare doppio clic su un file script.py equivale a invocarlo dalla shell con > py script.py. Se volete fare una prova, vi conviene modificare il nostro script test.py in questo modo:

import sys
import time

print('Sono eseguito da: ' + sys.executable)

time.sleep(3)

Questo metterà "in pausa" lo script per 3 secondi, il tempo sufficiente a permettervi di leggere il messaggio prima di terminare e quindi chiudere automaticamente la finestra della shell (ve l'avevamo detto: gli script non si invocano con il doppio clic. Adesso cominciate a capire perché).

Torneremo ancora sull'idea di fare doppio clic per eseguire uno script Python, dopo aver imparato qualcosa di più sui virtual environment e sul meccanismo degli import.

Associare i file .py all'editor, invece.

Ecco un suggerimento che forse vi conviene seguire. Siccome non vi capiterà mai di eseguire uno script Python facendo doppio clic (perché userete sempre la shell), allora potreste chiedervi se non c'è un uso migliore per il doppio clic su un file .py.

Molti programmatori associano semplicemente l'estensione .py all'editor preferito. In questo caso, quando fate doppio clic su uno script, non lo eseguite ma lo aprite con l'editor per modificarlo. In questo momento voi non avete ancora scelto un editor "da programmatore", ma quando succederà vi converrà tenere a mente questa possibilità. Dopo un po', diventa più naturale associare il doppio clic al concetto di "modificare uno script", e l'invocazione dalla shell al concetto di "eseguire uno script". Se state seguendo questi appunti passo-passo, probabilmente vi sarete già accorti che aprire ogni volta il vostro test.py con il Blocco Note per modificarlo è un po' complicato: e forse vi è già venuto in mente di associare .py al Blocco Note (notepad.exe) per fare più in fretta. Potete farlo per il momento, se volete: l'importante è che sia una cosa provvisoria. Non si usa il Blocco Note per programmare davvero.

I file .pyw.

Quando installate una versione di Python su Windows, avete a disposizione non una, ma due versioni dell'eseguibile dell'interprete: python.exe e pythonw.exe. Il primo è l'interprete che usate normalmente. Il secondo è identico al primo, tranne per il fatto che nasconde la finestra della shell.

Questo secondo interprete è chiaramente destinato agli utenti "normali" che devono eseguire un programma Python scritto da altri, e non saprebbero che farsene della finestra della shell aperta (certo, il programma dovrebbe avere una interfaccia grafica per comunicare con l'utente. Se invece il programma ha un'interfaccia testuale, allora la finestra della shell serve eccome!).

Come si fa a scegliere con quale dei due interpreti eseguire uno script? Se siete nella shell, ovviamente non è un problema: basta invocare > pythonw test.py (per il python di default). Ma esiste anche una versione "con la w" del launcher py, per cui potete invocare > pyw test.py o > pyw -2 test.py etc. Potete provarci: lo script viene eseguito, ma non potete vedere nessun output.

Chiaramente però non è questo lo scopo di pythonw.exe e pyw.exe. L'utente "normale" vuole fare doppio clic sul file dello script, come sappiamo. Per questo scenario, Windows registra un'estensione separata: .pyw invece di .py. In altre parole, vi basta modificare l'estensione del vostro file test.py in test.pyw, e Windows saprà che deve aprirlo con il launcher pyw.exe invece di py.exe. Valgono le stesse raccomandazioni fatte sopra per l'estensione .py: dovete controllare che .pyw sia effettivamente associato al launcher C:/Windows/pyw.exe, come descritto sopra.

Fatto questo, se volete testare il vostro script, vi conviene modificarlo ancora una volta, in questo modo:

import sys
import winsound

if 'Python27' in sys.executable:
    winsound.Beep(2000, 5000)
else:
    winsound.Beep(5000, 5000)

Siccome adesso non c'è un output scritto che potete vedere, questo script emette un tono più basso se viene eseguito da Python 2, e un tono più alto se viene eseguito da Python 3.

I file .pyc.

Occasionalmente vedrete dei file .pyc, con una icona leggermente diversa. Questi sono file Python pre-compilati per una esecuzione più veloce. Siccome contengono bytecode e non testo, non ha senso aprirli con l'editor. Potete associarli al launcher .py o all'interprete python.exe.

I file .pyz.

Questa possibilità esiste fin da Python 2.6, ma è stata potenziata e documentata meglio solo a partire da Python 3.5. In pratica è possibile comprimere i file degli script Python in archivi zip: l'interprete Python è in grado di eseguire anche questi archivi compressi. Se volete provare questa possibilità con il nostro breve script di test, potete fare così:

C:\test > py -m zipapp test.py -o test.pyz
C:\test > py test.pyz

La prima riga invoca il modulo zipapp della libreria standard per comprimere il nostro file di test; la seconda riga mostra che l'interprete Python è in grado di eseguire normalmente il file compresso risultante.

Ovviamente questa opzione ha più senso se volete comprimere una intera directory che contiene diversi script Python raccolti in un "progetto" (un'applicazione di qualche tipo). In questo modo potete distribuire il vostro lavoro come un singolo archivio compresso, che Python è in grado di eseguire senza bisogno di scompattarlo prima.

Se ritenete, potete associare i file .pyz al launcher .py o all'interprete python.exe.

Riassunto: che cosa vi conviene fare, in breve.

Queste note sono volutamente dettagliate, per farvi capire le opzioni possibili. Quello che vi conviene davvero fare, comunque, è in genere molto semplice:

  • Installate una versione di Python "recente" (preferibilmente 3.6 o 3.7), in modo che abbia il launcher .py. Possibilmente, installatela "for all users" e selezionate le opzioni di aggiungerla alla path di sistema e di registrare le estensioni.
  • Installate qualsiasi altra versione, se volete. Aggiungetela alla path di sistema, ma non registrate più le estensioni.
  • Controllate che le estensioni .py e .pyw siano associate ai launcher py.exe e pyw.exe. In ogni caso, potreste voler ri-associare i file .py al vostro editor preferito.
  • Per eseguire gli script, usate il launcher py dalla shell.

Se invece per qualche ragione volete installare solo Python 2, allora vi conviene:

  • Installare la versione più recente (Python 2.7), possibilmente "for all users", aggiungendola alla path di sistema e registrando le estensioni.
  • Controllare che .py e .pyw siano associate a python.exe e pythonw.exe rispettivamente. In ogni caso, vi conviene ri-associare i file .py al vostro editor preferito.
  • Per eseguire gli script, invocate python script.py dalla shell.

Riassunto: come funziona py (e python) in breve.

Riassumiamo anche i diversi modi con cui si usa il launcher. Per adesso è molto semplice, ma vedremo che la situazione si complicherà leggermente con i virtual environments.

  • py non qualificato (senza indicare un numero di versione): usare py script.py avvia uno script con la versione più recente di Python (o quella impostata da PY_PYTHON). Usate semplicemente py per avviare la shell di quell'interprete.
  • py qualificato: usare per esempio py -2 script.py avvia lo script con una versione specifica di Python. py -2 avvia la shell dell'interprete specificato.
  • python: usare python script.py avvia lo script usando il Python "di default", ovvero il primo interprete che Windows trova nella path di sistema (in genere, l'ultima versione che è stata installata). Un semplice python avvia la shell del Python di default.

Parte seconda: virtual environment.

Quanto abbiamo visto fino a questo punto è sufficiente per iniziare a programmare con Python, almeno fino a un punto ben preciso: la prima volta che vi trovate a dover installare un pacchetto esterno alla libreria standard.

Quando installate Python, installate anche la sua libreria standard: una grande famiglia di moduli pensati per risolvere ogni genere di problemi comuni, dalla matematica al logging, dai database al markup parsing, dalla concurrency alle regular expression, e molto altro. Tutto ciò che sta nella libreria standard è utilizzabile: basta importare quello che vi serve nel vostro script. Nelle diverse incarnazioni del nostro script test.py, ci è già capitato di importare i moduli sys, time, winsound.

Potete fare molta strada solo con la libreria standard. Se state imparando a programmare in Python, è possibile (e perfino consigliabile) limitarsi alla libreria standard per molti mesi, prima di iniziare a esplorare altro. Ma prima o poi vi troverete nella necessità di installare anche delle librerie esterne, per coprire nuovi scenari, o per fare le stesse cose in modo diverso e migliore.

Un chiarimento terminologico, prima di proseguire. Qui non stiamo parlando di installare "un programma", nel senso di un software compiuto destinato all'utente finale. Un "programma" scritto in Python si installa come un qualsiasi altro: per esempio, Calibre è un programma per la gestione di e-book, ed è scritto in Python. Se vi piace, potete scaricarlo e installarlo. Ciò che scaricate è il programma Calibre pacchettizzato e distribuito per l'utente finale. Noi però qui stiamo parlando di software scritto in Python e distribuito come una "libreria", o magari un "framework": si tratta di codice che non è destinato agli utenti finali, ma ai programmatori per aiutarli a scrivere altro codice. I moduli della libreria standard sono un esempio: sys, time, winsound etc. non sono programmi per l'utente, ma componenti da importare nei vostri programmi.

Installare librerie esterne in Python è veramente molto facile, al punto che il problema è che... ne installerete troppe. Nel corso del tempo è facile riempire la propria installazione Python con un mucchio di librerie esterne scaricate e installate per prova, per esigenze temporanee, per progetti poi chiusi o accantonati, etc. Inoltre, lavorando in certi ambiti (un esempio tipico: le applicazioni per il web) è facile trovarsi a dover installare decine di pacchetti esterni. La manutenzione di tutto questo può diventare un incubo.

Per questo bisogna imparare a far bene le cose fin dall'inizio. Prima di imparare a installare pacchetti esterni, dovete imparare a creare e gestire i virtual environment.

Che cosa è un virtual environment.

Un virtual environment (d'ora in poi "venv" per brevità) è una installazione isolata di Python, creata a partire dal Python "globale", di sistema che avete già installato. In concreto, è una directory separata in cui si copiano i file necessari all'esecuzione di Python e la sua libreria standard: successivamente è possibile installare i pacchetti esterni direttamente nel venv, invece che nel Python "principale".

I vantaggi dei venv sono molteplici: permettono di non inquinare l'installazione di Python con dozzine di pacchetti che magari servono solo a un progetto particolare; permettono soprattutto di tenere sotto stretto controllo i pacchetti che servono all'esecuzione di un determinato progetto (le sue "dependencies", come si chiamano). Quando un venv non serve più, semplicemente lo si cancella; se sbagliate a installare qualcosa, o non siete sicuri di aver fatto la cosa giusta, potete buttare via il venv e ricominciare daccapo; etc.

La strategia abituale è di creare un venv separato per ciascun nuovo progetto "importante". Potete naturalmente creare un venv di servizio generico da usare per gli script veloci, i progettini, gli esperimenti. Ma non appena un progetto cresce, e ha bisogno di "dependencies" esterne ben precise, è fondamentale creare un venv solo per lui.

Dove mettere i virtual environment.

Concretamente, i venv sono delle directory con dentro una copia di Python e della libreria standard (più precisamente: un puntatore ai file della libreria standard, per evitare di copiarli fisicamente. Ma questo è un dettaglio). Ci finiscono dentro poi tutti i pacchetti esterni che installerete via via. Potete creare un venv dove volete. Una soluzione abbastanza comune su Windows (copiando le convenzioni di Linux) è installarli in una apposita directory envs nella propria cartella personale (ovvero in %USERPROFILE%/envs).

Tenete conto che, lavorando, finirete per creare parecchi venv, e che ciascuno occupa spazio e comprende centinaia di file: se la vostra cartella personale è soggetta a backup periodico e non potete escludere %USERPROFILE%/envs dai backup (per esempio, lavorate su una macchina aziendale ed è complicato spiegarlo all'amministratore), può essere fastidioso.

Talvolta è preferibile una soluzione differente. Nel seguito di questi appunti useremo la directory D:/envs come base per i nostri venv. Questa potrebbe non essere una buona politica se la macchina è usata da più utenti, visto che in genere il drive D: viene lasciato come "terra di tutti". Ma è una path corta da scrivere nella shell, e in ogni caso se per voi non va bene potete adottare la soluzione che più vi fa comodo. Se volete seguire questi appunti passo-passo, create quindi una directory vuota D:/envs prima di procedere.

Creare e usare un virtual environment di Python 3.7.

Le versioni di Python più recenti (dalla 3.3 in poi) hanno un modulo venv nella libreria standard che permette appunto di creare i venv. Il procedimento è molto semplice: portatevi con la shell nella directory D:/envs, e invocate il modulo venv per creare il nuovo venv:

> cd d:/envs
D:\envs > py -3 -m venv test

Questo richiede qualche spiegazione aggiuntiva. Notate che abbiamo specificato l'opzione -3 del launcher py per indicare che vogliamo eseguire Python 3. L'opzione -m vuol dire che non ci interessa invocare la shell di Python, ma vogliamo invece che Python esegua un modulo in particolare: in questo caso, il modulo venv con l'argomento ulteriore test che è semplicemente il nome che vogliamo dare al venv che stiamo creando.

Con questo abbiamo creato un nuovo venv di nome test. Concretamente, questo significa che adesso esiste una directory d:/envs/test con dentro i file necessari a eseguire Python 3.7 e la sua libreria standard (controllate pure!).

Per "usare" un venv bisogna prima "attivarlo". Per questo scopo esiste un batch script activate.bat che viene sempre copiato nel processo di creazione del venv: potete usarlo in questo modo:

> d:/envs/test/scripts/activate
(test) >

Da una directory di lavoro qualsiasi, in questo modo avete attivato il venv. Notate che adesso il prompt indica la stessa directory di prima, ma preceduta dal nome del venv (test nel nostro caso): questo vuol dire che adesso state lavorando "dentro" il venv. Da un punto di vista concreto, vuol dire semplicemente che l'indirizzo dell'interprete Python del venv è stato aggiunto in testa alla path di sistema (potete controllare con un semplice echo %PATH%, se volete).

E questo a sua volta vuol dire che adesso tutte le invocazioni a py oppure python saranno indirizzate al Python del venv, invece che al Python di sistema. Potete verificarlo con il metodo già noto (questa volta lavoriamo direttamente dalla shell di Python, per cambiare un po'):

(test) > py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.executable)
d:\envs\test\Scripts\python.exe
>>> exit()
(test) > python
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.executable)
d:\envs\test\Scripts\python.exe
>>> exit()
(test) >

Come vedete, finché siete dentro al venv, le chiamate a py oppure python vengono dirottate sull'eseguibile Python che si trova dentro il venv. Notate però che se voi invocate il launcher specificando una versione particolare (per esempio py -2 oppure py -3), allora il launcher avvierà il Python di sistema, anche se siete dentro al venv.

Lo stesso capita se volete eseguire uno script: se invocate py test.py (oppure python test.py) da dentro un venv, lo script viene eseguito dall'interprete del venv.

Per uscire da un venv, basta invocare deactivate dalla shell (concretamente, esiste un bash script deactivate.bat che rimette a posto la path di sistema):

(test) > deactivate
> 

Una volta usciti dal venv, per cancellarlo completamente basta eliminare fisicamente la directory che lo contiene.

Creare un virtual environment di Python 2.7.

Python 2 non ha il modulo venv nella sua libreria standard: quindi occorre installarlo come pacchetto esterno. Per questo scopo esiste uno strumento apposito che si chiama Pip. Impareremo a capire come funziona tra non molto: per il momento, fidatevi e semplicemente

> pip2 install virtualenv

Questo scaricherà e installerà il pacchetto virtualenv nel votro Python 2 di sistema. Non avevamo detto che non bisogna mai installare pacchetti esterni nel Python "globale", ma solo dentro ai venv? Sì ma questa è un'eccezione: d'altra parte, se non installiamo globalmente almeno il pacchetto necessario per creare i venv, come possiamo installare tutto il resto dentro ai venv?

Una nota: nella stragrande maggioranza dei casi, avrete una sola versione di Python 2 installata (tipicamente, Python 2.7). Se per qualche ragione particolare invece avete installato due versioni di Python 2 (per esempio, Python 2.7 e Python 2.6), allora pip2 non basta a identificarle in modo univoco. In questo caso, usate invece pip2.7 per installare virtualenv in Python 2.7, e poi pip2.6 per installarlo in Python 2.6.

Il pacchetto virtualenv, tra le altre cose, installa uno script virtualenv.exe nella directory Scripts del vostro Python 2 (nel nostro caso, quindi, C:/Python27/Scripts/virtualenv.exe: potete controllare). Per creare un venv di Python 2, quindi, vi basterà:

> cd d:/envs
D:\envs > virtualenv test_py2

Questo crea un venv di Python 2 di nome test_py2 in d:/envs: fisicamente, una directory d:/envs/test_py2 con l'interprete di Python 2 e tutto il resto.

Ancora una nota (che prosegue quella di prima): se avete una sola installazione di Python 2, come in genere avviene, allora avete anche un solo virtualenv.exe che Windows può trovare nella path di sistema (ricordiamo infatti che Python 3 non ha nessun virtualenv, ma un modulo venv). Se però avete due o più versioni di Python 2 installate (2.6 e 2.7 per esempio), allora dovete per forza specificare con quale virtualenv volete creare il vostro venv. Per esempio, per Python 2.7 sarebbe D:\envs > c:/python27/scripts/virtualenv test_py2.

Una volta creato il venv, le operazioni successive sono le stesse che abbiamo visto per i venv di Python 3. Per attivarlo basterà:

> d:/envs/test_py2/scripts/activate
(test_py2) >

Per disattivarlo:

(test_py2) > deactivate
> 

Per rimuoverlo, basta cancellare la directory in cui risiede.

Eseguire script nei virtual environment.

Potete avviare la shell Python o eseguire uno script quando siete nel contesto di un venv. Potete usare il launcher py o l'invocazione diretta dell'interprete python.

Se invocate py all'interno di un venv, senza specificare un numero di versione, il launcher vi restituisce l'interprete Python che trova nel venv. Se invece specificate una versione (per esempio, py -2), allora il launcher sceglie sempre l'interprete "globale" di sistema (anche se il Python del venv è lo stesso!). Per esempio, se siete all'interno di un venv di Python 3, allora:

  • py test.py esegue il modulo con il Python 3 del venv;
  • py -3 test.py lo esegue con il Python 3 di sistema;
  • py -2 test.py, naturalmente, lo esegue con il Python 2 di sistema.

Se invece eseguite il modulo con python test.py, allora sicuramente avrete l'interprete del venv, perché è il primo che Windows trova nella path di sistema.

Potete testare voi stessi tutte le varianti possibili, creando venv di Python 3 e Python 2, e poi avviando il nostro test.py dentro e fuori dal venv, in vari modi. Vi conviene tornare alla prima versione del modulo (quella che aveva semplicemente le righe import sys; print(sys.executable)).

Una nota: a questo punto dovrebbe essere ovvio perché "fare doppio clic" su uno script Python non è il modo giusto per eseguirlo. L'utilizzo dei venv costringe a usare la shell: facendo doppio clic, lo script viene sempre interpretato dal Python di sistema. In teoria potreste ri-associare manualmente le estensioni .py e .pyw all'interprete Python del venv: in pratica però costruirete e distruggerete venv di continuo, e passerete sempre da un venv all'altro... cambiare le associazioni ogni volta sarebbe assurdo.

Riassunto: come funziona py (e python), con e senza i venv.

Aggiorniamo la nostra tabella dei diversi modi in cui si usa il launcher.

  • py non qualificato (py script.py):
    • fuori da un venv: avvia lo script con la versione più recente di Python (o quella impostata da PY_PYTHON);
    • dentro il venv: avvia lo script con la versione del venv.
  • py qualificato (es. py -3 script.py):
    • avvia lo script sempre con la versione specifica del Python di sistema, anche se siete dentro un venv.
  • python (python script.py): avvia sempre lo script con il primo interprete che Windows trova nella path, e pertanto:
    • fuori da un venv, con il Python "di default"
    • dentro un venv, sempre con il Python del venv.

Parte terza: installare pacchetti esterni con Pip.

Dopo aver capito come si creano i venv, è il momento di usarli per lo scopo per cui sono nati: mantenere "ambienti" separati e isolati in cui installare tutte le "dependencies" necessarie al progetto a cui state lavorando.

PyPI: la repository ufficiale delle librerie Python.

Per prima cosa, dovete sapere che cosa è PyPI (Python Package Index): si tratta della più grande e "ufficiale" repository di software scritto in Python. È ufficiale nel senso che è mantenuta dalla stessa Python Software Foundation che gestisce lo sviluppo di Python, ed è sicuramente il punto di riferimento per tutti gli sviluppatori Python.

In pratica coloro che, dopo aver scritto una libreria (che può essere un semplice modulo come un complesso framework) desiderano distribuirla, possono registrarla e caricarla su PyPI come un pacchetto installabile. Chi desidera poi installare il pacchetto può cercarlo e scaricarlo su PyPI.

PyPI ha un'interfaccia web che offre varie possibilità di ricerca e, volendo, di scaricamento diretto dei pacchetti. In pratica però queste operazioni sono sempre effettuate con il package manager Pip.

Pip: il package manager ufficiale di Python.

Pip è un package manager per pacchetti Python: è "ufficiale" perché è entrato a far parte della libreria standard, e quindi dovrebbe essere a disposizione con la vostra installazione di Python (dalla versione 3.4 in poi, e anche nella 2.7. Se avete una versione più vecchia, Pip va installato separatamente).

Pip è un modulo della libreria standard, ma esiste anche un eseguibile pip.exe nella directory Scripts della vostra installazione Python, che è leggermente più comodo da usare. Per esempio, potete usare direttamente pip install invocando l'eseguibile, invece di py -m pip install invocando l'interprete Python e chiedendogli di eseguire il modulo pip.

Abbiamo già usato Pip per installare il pacchetto virtualenv nel Python 2 di sistema. Come abbiamo detto, è bene tuttavia installare i pacchetti sempre in un venv.

Come primo esempio, proviamo a installare Arrow: si tratta di un pacchetto per la gestione delle date. Se non lo avete già fatto, create un venv di Python 3 (chiamiamolo test) e usiamo pip install:

> cd d:/envs
D:\envs > py -3 -m venv test
> d:/envs/test/scripts/activate
(test) > pip install arrow
[...]

Come vedete la sintassi è elementare: invochiamo pip.exe seguito dall'opzione install, seguita dal nome del pacchetto che vogliamo installare. Pip si occupa di tutto per noi: cerca il pacchetto su PyPI, sceglie la versione più aggiornata, la scarica e la installa. Se c'è bisogno (come in questo caso) di installare degli altri pacchetti mancanti per il funzionamento di Arrow, allora Pip cerca, scarica e installa anche questi.

Se adesso aprite una shell nel venv e provate a importare e usare Arrow, scoprirete che... funziona, naturalmente!

(test) > py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import arrow
>>> print(arrow.utcnow()) 

Niente di difficile. Se adesso uscite dal venv (deactivate), e provate di nuovo ad aprire una shell Python (py -3) e importare Arrow, otterrete invece un ModuleNotFoundError. Come promesso, Arrow è stato installato solo nel venv, e non nel Python di sistema.

La stessa cosa, ovviamente, vale per i vostri script. Modificate ancora una volta il vostro test.py, come segue:

import sys
import arrow

print(sys.executable)
print(arrow.utcnow())

Adesso se lo eseguite da dentro il venv, funziona:

(test) > cd c:/test
(test) C:\test> py test.py
[...]

Ma fuori dal venv, no:

(test) C:\test> deactivate
C:\test> py test.py
[...]
ModuleNotFoundError: No module named 'arrow'

La documentazione completa di Pip spiega nel dettaglio tutte le opzioni possibili. È importante ricordare, oltre a pip install, anche pip uninstall <package> e pip upgrade <package> per aggiornare. È importante la possibilità di specificare la versione del pacchetto da installare, in modo più o meno preciso. Per esempio,

pip install arrow==0.4.4
pip install 'arrow>=0.5'

e così via.

Una nota ancora: nei rari casi in cui effettivamente serve installare un pacchetto "globalmente", e non all'interno di un venv, state attenti a usare pip install quando avete molteplici versioni di Python installate. La semplice invocazione a pip utilizza il primo pip.exe che Windows trova nella path di sistema: è chiaro che quando siete all'interno di un venv, questo è sempre il pip.exe del venv, e quindi pip install "funziona e basta". Ma fuori da un venv, pip potrebbe non riferirsi al pip.exe che volete voi. Per fortuna oltre a pip.exe esistono sempre anche le versioni "numerate" degli eseguibili di Pip: per esempio, in una installazione di Python 2.7 troverete anche pip2.exe e pip2.7.exe. Quindi, se siete fuori da un venv, dovete invocare le versioni numerate per essere sicuri di usare il Pip giusto: invece di pip install, usate pip2 install, pip3.7 install, etc., a seconda di dove volete installare il pacchetto. Tutto questo, ripetiamo, non è necessario all'interno di un venv (ovvero, nella quasi totalità dei casi): all'interno di un venv, pip install fa sempre la cosa giusta.

Una nota ancora per concludere: se avete installato Python 3 "for all users", probabilmente lo avete installato in C:/Program Files. In questo caso, naturalmente, l'installazione di pacchetti "globali" con pip3 install fallirà con un PermissionError: [WinError 5]: dovete installare da una shell "privilegiata" (ovvero con privilegi da amministratore). Ancora una volta, precisiamo: è molto raro incontrare questo problema, perché in genere installerete pacchetti solo nei venv, e i venv naturalmente risiedono in una directory per la quale avete i necessari permessi di scrittura.

Liste di "requirements".

Pip mantiene un registro dei pacchetti. Potete verificare quali pacchetti avete installato con pip freeze:

(test) > pip freeze

Di solito, dopo aver installato i pacchetti necessari in un venv, si "salva" la configurazione raggiunta in un file di testo:

(test) > pip freeze > requirements.txt

Qui naturalmente > è il comando standard per re-direzionare l'output della shell, e requirements.txt è il nome che per convenzione si dà a questo tipo di file. Un file requirements.txt non è solo un promemoria per noi: è l'impronta digitale del nostro venv, ed è anche la ricetta per ri-crearlo identico a partire da zero. Infatti pip install ha anche l'opzione di installare in un colpo solo tutti i pacchetti che trova elencati in un file di testo.

Potete fare la prova. Supponiamo che abbiate messo il vostro requirements.txt nella directory c:/test che abbiamo usato finora come base d'appoggio. Ora, uscite dal venv test, createne un altro (poniamo, in d:/envs/test2), ed entrateci. Adesso tutto ciò che dovete fare è:

(test2) > cd c:/test
(test2) C:\test > pip install -r requirements.txt

La chiave qui è l'opzione -r di pip install, che dice a Pip di installare tutto ciò che trova elencato nel file specificato (in questo caso, requirements.txt). Alla fine della procedura, vi ritroverete un venv completo di tutti i pacchetti dichiarati nel requirements.txt (potete verificare con pip freeze, naturalmente).

La lista di requirements che ottenete da pip freeze è molto specifica: per ciascun pacchetto è indicata la versione esatta che avete installato. Questo è utile se si desidera ri-creare ogni volta lo stesso preciso venv. Tuttavia, talvolta questo non è davvero ciò che volete: potreste voler installate ogni volta le versioni più recenti dei pacchetti. Per questo vi basterà correggere manualmente il vostro requirements.txt togliendo le versioni, e lasciando solo l'elenco dei pacchetti:

arrow
python-dateutil
six

In questo modo pip install -r requirements.txt cercherà automaticamente sempre le versioni più aggiornate. Il formato di un requirements.txt può essere molto semplice (un elenco di pacchetti), molto specifico (il risultato di un pip freeze) o... raffinato: rimandiamo alla documentazione per tutte le sottigliezze.

Una particolare sottigliezza che conviene tenere a mente è che i file dei requirement sono componibili tra loro, nel senso che un file può specificare di installare anche i pacchetti elencati in un altro file. Questo torna utile in molti scenari. Per esempio: un progetto richiede un elenco di pacchetti comuni, e inoltre alcuni pacchetti aggiuntivi che si usano solo in fase di sviluppo, o di test, ma che non sono necessari per la versione "pubblica" del progetto. In questo caso, potete indicare i pacchetti comuni in un requirements.txt come al solito. Poi potete creare un secondo file (per esempio requirements_devel.txt) in cui scrivete i pacchetti aggiuntivi:

-r requirements.txt
pacchetto_aggiuntivo1
pacchetto_aggiuntivo2
...

Notate l'opzione iniziale -r che rimanda a requirements.txt: potete specificare la path assoluta di requirements.txt, o preferibilmente la sua path relativa al file corrente, che in questo caso è requirements_devel.txt (ma mettete tutti i file di requirements nella stessa directory e siete a posto). Adesso potete creare il vostro venv di sviluppo con pip install -r requirements_devel.txt, che installerà anche i pacchetti elencati in requirements.txt.

Una strategia comune, al momento di iniziare un nuovo progetto, è di creare un venv apposito. Man mano che si installano dei nuovi pacchetti necessari al progetto, si rigenera il requirements.txt con pip freeze. Il file dei requirements è quindi tutto ciò che occorre per definire l'ambiente Python necessario a far funzionare il codice di quel progetto. Il venv si può distruggere e ricreare da zero, con un semplice pip install -r requirements.txt.

A questo punto, è importante sottolineare che non bisognerebbe mai manipolare direttamente la directory del venv (aggiungere, togliere, spostare dei file al suo interno). Il motivo è appunto questo: tutto il contenuto del venv deve dipendere esclusivamente da un requirements.txt. Il nostro progetto (i moduli Python che scriviamo, la documentazione, i file di configurazione e accessori...) deve sempre risiedere in una directory separata dal venv. Anche il file dei requirement risiede nella directory del progetto. Vedremo in seguito come strutturare un progetto Python in modo razionale.

Installare pacchetti locali.

Pip è in grado di installare pacchetti che avete scaricato in precedenza da PyPI, ma anche da altre repository purché i pacchetti siano conformi alle specifiche richieste da Pip/PyPI. Molto raramente potrebbe capitarvi di installare un pacchetto che non è stato caricato su PyPI, ma che trovate solo (per esempio) su sito dell'autore. Oppure potreste volervi fare una piccola collezione di pacchetti che installate frequentemente, in modo da non doverli scaricare tutte le volte da PyPI. Una terza possibilità è che dobbiate installare dei pacchetti pre-compilati non ufficiali, che non trovate quindi su PyPI: approfondiremo tra poco questo caso.

Vi conviene prima di tutto creare una directory d:/envs/packages in cui scaricare e conservare i vostri pacchetti preferiti. Potete scaricare direttamente dal sito di PyPI, ma potete anche lasciare che sia Pip a fare il lavoro per voi: Pip ha infatti un'opzione per scaricare senza installare. Facciamo una prova, questa volta con la nota libreria Requests (serve a manipolare richieste HTTP). Lavoriamo sempre all'interno del nostro venv di Python 3: anche se Pip non installerà subito il pacchetto, è importante che sappia per quale versione di Python deve scaricarlo.

(test) > pip download requests -d d:/envs/packages

L'opzione -d specifica una directory di destinazione; se non la indicate, Pip scaricherà il pacchetto nella directory corrente. Se adesso guardate dentro d:/envs/packages, troverete il pacchetto scaricato. Si tratta di una Wheel (riconoscibile dall'estensione .whl): è il formato oggi più comune per i pacchetti Python, e ne parleremo ancora in seguito. Per il momento, una raccomandazione: non dovete cambiare il nome del file scaricato. In una Wheel il nome del file è significativo, e Pip non potrà installarlo correttamente se lo modificate.

Una volta scaricato il pacchetto, potete installarlo con Pip senza più bisogno della connessione internet:

(test) > pip install d:/envs/packages/requests-2.13.0-py2.py3-none-any.whl

Come vedete, basta specificare la path del pacchetto (non è necessario che sia una path assoluta: basta la path relativa alla directory corrente). Potete anche scrivere le path dei pacchetti locali che desiderate in un requirements.txt, e installare in un colpo solo tutto quanto con pip install -r requirements.txt.

Wheel e pacchetti binari precompilati.

La procedura che abbiamo descritto fin qui funziona per installare pacchetti che sono scritti completamente in Python. Ma occasionalmente (per fortuna sempre più di rado) pip install fallisce con una serie di messaggi di errore piuttosto complicati, ma che in sostanza ci avvertono che non è possibile "compilare" i pacchetti necessari.

Che cosa è successo? Molti pacchetti, in realtà, non sono scritti solo in Python, ma ospitano anche qualche estensione scritta in C/C++. Fino a qualche anno fa, il formato di distribuzione dei pacchetti Python (le "egg", che si trovano ancora occasionalmente) non prevedeva un modo per distribuire pacchetti con estensioni già compilate. Quindi, le estensioni in C dovevano essere compilate da voi al momento dell'installazione. Questo non è un problema sui sistemi Linux, che tradizionalmente hanno un compilatore di default pronto all'uso: in questo caso, Pip si rivolge al compilatore, compila le estensioni C, e installa il pacchetto senza problemi.

Windows invece non ha un compilatore di default, e quindi Pip scarica correttamente il pacchetto giusto, ma al momento di compilare le estensioni non sa più come procedere.

Da qualche anno Python ha introdotto un nuovo formato per distribuire i pacchetti, che ormai ha quasi del tutto sostituito il precedente: le Wheel, che consentono tra l'altro di pre-compilare le estensioni C. Tuttavia occasionalmente pip install potrebbe ancora trovare su PyPI solo vecchi pacchetti non pre-compilati. O magari Pip trova una wheel, ma non quella pre-compilata per la vostra particolare versione di Python. In casi del genere, possiamo rimediare seguendo una delle due strade:

  1. installiamo un compilatore C, e compiliamo a mano le estensioni che ci servono. In linea di principio, questa è una strada perfettamente percorribile. Tuttavia, compilare su Windows richiede un po' di esperienza e capacità di affrontare corner case fastidiosi;
  2. nella maggior parte dei casi, qualcuno ha già fatto il lavoro al posto nostro. Si tratta quindi di trovare e scaricare un pacchetto con le estensioni già compilate, che Pip può quindi installare senza problemi.

Vedremo subito come percorrere la seconda strada - ma prima, una legittima domanda: perché gli sviluppatori non distribuiscono su PyPI direttamente i pacchetti con le estensioni già compilate? In primo luogo, questa possibilità è arrivata solo di recente, con le wheel. Ma soprattutto, è possibile e scusabile che gli sviluppatori non abbiano voglia di supportare diverse versioni dello stesso pacchetto, pre-compilate per ciascuna diversa piattaforma. Spesso è possibile trovare le wheel compilate solo per le piattaforme che gli sviluppatori ritengono più interessanti o accessibili per loro. Talvolta esistono wheel compilate solo per certe versioni di Python, e non per altre. In particolare, potrebbe essere leggermente più complicato trovare wheel compilate per Python 3.5/6/7. Infatti ricordate che queste versioni di Python sono compilate con Visual Studio 2015. Uno scenario frequente è che il pacchetto, per quanto riguarda il solo codice Python, sia perfettamente compatibile tra Python 3.4 e Python 3.5+. Tuttavia, se il pacchetto contiene delle estensioni C, lo sviluppatore deve ugualmente compilarlo due volte con un compilatore diverso (per supportare la 3.4 e la 3.5+). Molti sviluppatori, comprensibilmente, potrebbero non aver voglia di tenere entrambi i compilatori installati e fare due volte il lavoro. Va detto comunque che, man mano che Python 3.4 esce di scena, le wheel precompilate con Visual Studio 2015 stanno ormai diventando la norma.

In ogni caso, ci sono diverse opzioni da tentare.

  • La wheel precompilata per la vostra piattaforma è già su PyPI. Questa è in realtà una opzione-zero che dovreste aver già controllato, perché in questo caso pip install funziona senza problemi. Tuttavia raramente su PyPI si trovano altre distribuzioni precompilate, solo non come wheel (tipicamente degli .exe, cfr. sotto, punto 5): quindi, anche se pip install fallisce, una ricerca manuale su PyPI può essere utile.
  • Il pacchetto "problematico" è una dependency di un altro pacchetto che state cercando di installare da PyPI. In casi del genere, prendete nota dei pacchetti che Pip non riesce ad installare da PyPI, cercateli e installateli manualmente, e poi ripetete l'installazione del pacchetto di partenza.
  • La wheel precompilata si trova sulla raccolta non ufficiale di Christoph Gohlke. Questo sito è una vera miniera d'oro per chi sviluppa in Python su Windows. Il buon Chris mantiene da anni una raccolta di decine di pacchetti precompilati, per varie versioni di Python e diverse piattaforme (32 e 64 bit). Semplicemente, cercate il pacchetto che vi interessa con ctrl+F nel vostro browser, assicuratevi di scaricare la versione giusta per voi, e installate dal file locale come abbiamo visto sopra. Va detto che la raccolta di Chris diventa (per fortuna!) sempre meno utile, man mano che gli sviluppatori mettono a disposizione le wheel precompilate su PyPI: tuttavia spesso sul sito di Chris trovate le wheel compatibili con le versioni più vecchie di Python, che gli sviluppatori non coprono direttamente. Questo sito è assolutamente da tenere nei bookmark.
  • La wheel precompilata si trova sul sito dello sviluppatore. Questo è raro: se lo sviluppatore si è dato la pena di produrre una wheel precompilata, allora deve averla messa anche su PyPI, e voi dovreste già averla trovata con pip install. Può capitare però, per esempio, che la libreria che vi interessa sia ancora in fase di sviluppo, e non sia disponibile su PyPI. Talvolta inoltre lo sviluppatore non produce delle wheel precompilate, ma sul suo sito si trovano altre indicazioni utili, per esempio link a contributori del progetto che mantengono versioni "non ufficiali" compilate, etc.
  • Sul sito dello sviluppatore (o siti collegati di contributori etc.; talvolta, anche su PyPI) si trova non la wheel precompilata, ma comunque un installer .exe. Questa era la tecnica più diffusa fino a poco tempo fa, anche perché era in pratica l'unico modo di mettere a disposizione pacchetti precompilati per Windows. L'aspetto negativo è che se fate doppio clic su questi .exe, si installano solo "globalmente" ignorando i venv. L'aspetto positivo è che molto spesso si tratta solo di pacchetti .egg (il vecchio modo di creare pacchetti in Python) raccolti in un file .zip eseguibile: in questo caso è facile convertirli in moderne wheel. Tutto quello che occorre, una volta scaricato manualmente il pacchetto, è dare il comando wheel convert pacchetto.exe per ottenere un wheel installabile poi con Pip. La libreria necessaria per l'operazione, Wheel, dovrebbe essere installata di default con Pip. Altrimenti, basta installarla con pip install wheel. Se la trasformazione da .exe a .whl non riesce, vi resta ancora una possibilità: usate il pacchetto .exe, ma costringetelo a installarsi in un venv anziché globalmente. Il trucco è non fare doppio clic sull'eseguibile, ma lanciarlo dalla shell... dopo aver attivato un venv! Di solito l'installer si limita a cercare Python nella path di sistema, e siccome l'attivazione del venv inserisce il suo interprete Python in testa alla path, il gioco è fatto. In genere funziona: se però l'installer .exe fa delle cose insolite (guarda il registro di configurazione, copia dei file in directory predefinite, etc...), allora bisogna rassegnarsi.

Se cercate delle wheel in rete da scaricare manualmente, fate attenzione a scegliere il pacchetto giusto: i nomi dei file delle wheel sono significativi e riportano la versione del pacchetto e con quali versioni di Python è compatibile. pip install e pip download vi procurano automaticamente la versione giusta, ma voi dovete scegliere tra le opzioni possibili.

Una volta scaricato il pacchetto, potete installarlo con Pip dal file locale, come visto sopra. Se adesso chiedete un pip freeze, noterete che il pacchetto che avete installato a mano è regolarmente elencato insieme agli altri. Di conseguenza, potete anche generare un normale file di requirements (pip freeze > requirements.txt). Tuttavia, se in futuro volete usare il file di requirements per re-installare l'ambiente del venv (pip install -r requirements.txt), questo potrebbe non funzionare: Pip cercherebbe i pacchetti richiesti su PyPI, e non troverebbe quelli installati manualmente.

L'unica soluzione è correggere il file requirements.txt, e specificare il pacchetto locale dove necessario: il vostro file potrebbe quindi avere questo aspetto:

# pacchetti "pure-python" da cercare su PyPI:
pacchetto1
pacchetto2
# etc etc

# pacchetti binari da installare localmente:
d:/envs/packages/pacchetto3.whl
d:/envs/packages/pacchetto4.whl
# etc etc

Potete chiamare requirements_local.txt questo file di requirements specifico per il vostro sistema, e generare poi un requirements.txt "ufficiale" con pip freeze da includere nel vostro progetto se intendete pubblicarlo.

Pacchetti ausiliari di uso comune.

Quando installate dei pacchetti in un venv, questi sono ovviamente disponibili solo nel venv in cui li avete installati. È possibile tuttavia creare un venv con l'opzione --system-site-packages, che permette al venv di utilizzare anche i pacchetti installati nel Python di sistema da cui è stato creato.

Se per esempio create un venv così:

> cd d:/envs
D:\envs > py -3 -m venv my_venv --system-site-packages

allora il venv my_venv avrà accesso anche ai pacchetti installati nel Python 3 di sistema. Ma non abbiamo detto e ripetuto che non bisognerebbe mai installare pacchetti nel Python di sistema? Infatti: quindi, anche --system-site-packages non andrebbe usata affatto, o con estrema cautela.

C'è però uno scenario comune, in cui tutto questo è permesso e forse perfino consigliabile. Vi troverete spesso a dover installare una serie di pacchetti ausiliari che non sono necessari per eseguire il codice del vostro progetto, ma che comunque vorrete installare per aiutarvi nello sviluppo. Per esempio, un linter come Pep8 o PyLint; pacchetti che vi aiutano con i test, come Pytest, Nose o Fixtures; oppure ancora Sphinx per generare la documentazione; e altri ancora (parleremo di questi aspetti e di questi pacchetti nelle sezioni successive).

Ci sono due strategie per gestire questi pacchetti ausiliari. La prima, più semplice, è di installarli con Pip in ciascun venv che create. Tutt'al più, potete risparmiare il tempo di download scaricando una volta per tutte le wheel necessarie, e chiedendo a Pip di installare dal file locale. Dovete solo fare attenzione a un dettaglio: siccome non sono pacchetti necessari a eseguire il vostro codice, non dovreste includerli nel requirements.txt "pubblico" del vostro venv: potete creare un requirements_local.txt (o requirements_devel.txt) con tutti i pacchetti che servono solo a voi, e popolare il venv con quello.

La seconda strategia è quella di installare questi pacchetti ausiliari di uso comune nel Python di sistema, e poi creare i vostri venv con l'opzione --system-site-packages: in questo modo i venv possono attingere anche ai pacchetti ausiliari che vi servono per lo sviluppo. In questo modo vi risparmiate la piccola noia di installare gli stessi pacchetti in tutti i venv. Una cautela: come vedremo, molti di questi pacchetti potrebbero essere utilizzati e integrati nel vostro editor preferito: in genere gli editor evoluti possono essere istruiti sul venv di cui ha bisogno il codice su cui state lavorando. Se però il venv utilizza anche dei pacchetti globali, controllate se l'editor è in grado di capire dove trovarli: in genere non ci sono problemi, ma nei casi più complicati la documentazione dell'editor dovrebbe aiutarvi.

È importante in ogni caso ribadire un concetto: usate (eventualmente) questa strategia esclusivamente per i pacchetti ausiliari che non servono per far funzionare il codice dei vostri progetti, ma che servono solo a voi per lo sviluppo. Tutte le "dependencies" necessarie al vostro progetto devono essere installate nel venv ed elencate nel requirements.txt.

Riassunto: installare pacchetti.

Ripetiamo in breve i punti fondamentali:

  • Dedicate un venv a ciascun progetto. Potete creare anche uno o più venv generici per semplici script, per valutare nuovi pacchetti, etc. Ma non installate pacchetti nelle versioni "globali" di Python.
  • Installate con pip install: quasi sempre è la cosa giusta e la più facile.
  • Quando occasionalmente questo non funziona, cercate in rete le wheel precompilate del pacchetto che volete installare: scaricatele manualmente e installatele con Pip.
  • Generate un requirements.txt con pip freeze: questo file è la ricetta per creare il venv del vostro progetto. Il contenuto della directory del venv dovrebbe dipendere solo dal requirements.txt: non dovete mai modificare manualmente il venv.

Che cosa non sono i venv.

Prima di abbandonare l'argomento venv, è forse opportuno inserire alcune note di carattere più avanzato, che un principiante potrebbe tenere a mente per il futuro. Occorre tener presente che i venv Python non sono (e non vogliono essere) una soluzione completa di virtualizzazione: si tratta solo di un meccanismo, anche abbastanza poroso, per tenere separati i pacchetti Python occorrenti in un progetto. Il resto dell'ambiente di lavoro in cui il progetto è immerso non è controllabile con i venv. Un requirements.txt non può elencare le risorse esterne necessarie, come i file da aprire o le connessioni ai database; i venv non conservano le variabili d'ambiente, né qualsiasi altra informazione pertinente al vostro sistema operativo, al file system, all'hardware impiegato; un file di requirements, di per sé, è indifferente perfino alla versione di Python su cui state lavorando.

Se tutto questo per il vostro progetto è indifferente, allora nessun problema. Ma se avete bisogno di un controllo maggiore, dovreste rivolgervi a una soluzione di virtualizzazione più completa, come per esempio un container Docker. Una "virtual machine" di qualche tipo potrebbe aiutarvi sia in fase di sviluppo, per "congelare" lo status del sistema su cui lavorate; sia in fase di distribuzione della vostra applicazione, per garantire build deterministiche e/o per replicare fedelmente le caratteristiche della macchina che ospiterà il vostro software in produzione.

Un altro aspetto importante da ricordare è che Pip e i venv fanno molto poco per aiutarvi ad affrontare la variegata classe di problemi nota informalmente come "dependency hell". In sostanza, con Pip avete solo due alternative. Potete specificare nel requirements.txt solo i pacchetti principali che vi occorrono, senza numeri di versione: in questo modo, lasciate a pip install il compito di scaricare anche le dependency secondarie (i pacchetti che servono ai pacchetti che servono a voi!) e installare le versioni più aggiornate ogni volta che ri-create il venv. In questo modo però non avete una build deterministica: se una nuova versione di un pacchetto introduce una incompatibilità con il vostro codice, il risultato potrebbe essere imprevisto. In linea di principio, far girare il vostro codice produce risultati diversi in tempi diversi.

Oppure potete elencare tutti i pacchetti con le loro versioni esatte, come risultano da un pip freeze. In questo caso vi garantite una build deterministica, ma lo svantaggio è che dovete gestire manualmente il requirements.txt tutte le volte che volete aggiornare un pacchetto, modificando il numero di versione di questo e di tutte le sue dependency.

I moduli pip e venv della libreria standard sono sicuramente sufficienti per i principianti e anche per i più esperti, almeno nella maggioranza dei casi. Esistono comunque soluzioni più avanzate che prima o poi potreste voler prendere in considerazione: in questo periodo lo strumento di packaging più valido e popolare nel mondo Python è diventato Pipenv di Kenneth Reitz, ormai adottato come raccomandazione ufficiale della Python Packaging Authority. Prima o poi lo incontrerete sicuramente sulla vostra strada, visto che è usato/supportato anche da importanti PaaS come Heroku, PythonAnywhere e progressivamente tutti gli altri.

Parte quarta: intestazioni nei file.

Uno script Python è un file di testo che contiene il vostro codice, nulla di più. Tuttavia esistono alcune convenzioni che potete, e in qualche caso dovete, rispettare. Come minimo dovreste conoscerle, in modo da capire che cosa significano certe annotazioni che trovate nei programmi altrui.

La shebang: dichiarare che lo script deve essere eseguito da Python.

Le shebang sono una convenzione molto comune nel mondo Linux (per gli script in genere, e non solo quelli in Python). Fino a poco tempo fa, non avevano nessuna importanza per Python su Windows: era utile comunque inserirle per venire incontro agli sviluppatori Linux che eventualmente avrebbero usato i nostri script. Tuttavia, nelle versioni più recenti anche il launcher py ha imparato a tenere conto delle shebang in certe situazioni: a maggior ragione quindi bisogna sapere che cosa sono e come usarle.

L'idea della shebang è di fornire all'ambiente circostante (la shell del sistema operativo, tipicamente) informazioni su come deve essere interpretato lo script: specificare che si tratta di uno script Python (non Perl, per esempio); e dichiarare almeno entro certi limiti da quale interprete Python dovrebbe essere eseguito, nel caso che più di uno sia disponibile. Ne consegue che le shebang hanno senso, e dovrebbero essere usate, solo per gli script che vanno effettivamente eseguiti dall'interprete (script stand-alone, o script che costituiscono l'entry point della vostra applicazione). Se uno script è fatto esclusivamente per essere importato da altri script Python, allora non ha senso mettere la shebang.

Una shebang, se esiste, deve essere (rigorosamente) la prima riga del file, e deve iniziare con i caratteri #!. Dopo di che, potrebbe indicare la path dell'interprete Python (magari in un venv) che vogliamo che esegua lo script: questo però avrebbe senso solo nella nostra particolare configurazione, e quindi non è consigliabile, tranne magari che per script molto specifici, che useremo solo noi. In genere si preferisce indicare una path "virtuale", o comunque più generica.

Il launcher py riconosce i seguenti tipi di shebang (che naturalmente sono validi anche nel mondo Linux):

  • #! python: questa è l'indicazione più generica possibile, e segnala semplicemente che si tratta di uno script Python, senza dare ulteriori indicazioni.
  • #! /usr/bin/python oppure #! /usr/local/bin/python (più frequentemente la prima, però): queste sono le path dove su Linux ci si aspetta di trovare interpreti Python. Questa shebang segnala che lo script dovrebbe essere eseguito dal Python di sistema, quello che si trova in genere installato di default su Linux.
  • #! /usr/bin/env python: questa shebang segnala che lo script dovrebbe essere eseguito da un interprete Python che si trova in un "ambiente preparato", ovvero un venv. Quale ambiente preparato? Non sta alla shebang specificare ulteriormente. Su Linux, la shebang invoca il programma env che a sua volta effettua una ricerca nella path di sistema per trovare un python. Su Windows, vedremo che il launcher py fa praticamente lo stesso. Si suppone che quello trovato da env sia l'ambiente da usare: deve essere stato opportunamente preparato grazie ad altre istruzioni su quali librerie installare (per esempio, un requirements.txt); e deve essere stato opportunamente predisposto (per esempio manipolando la path di sistema, ovvero attivando un venv) prima di eseguire lo script. Ciò che di sicuro la shebang ci fa sapere è che il Python "di default" e la sua libreria standard non bastano a eseguire lo script.

Inoltre, è anche possibile usare queste shebang con un numero di versione: per esempio potete indicare !# python2, oppure #! /usr/bin/python3.5, e così via. Tuttavia la shebang #! /usr/bin/env python non dovrebbe mai essere "versionata": in teoria la versione di Python da usare dovrebbe far parte delle istruzioni per creare l'"ambiente preparato", e quindi la shebang non deve dare ulteriori specificazioni. Tuttavia può capitare lo stesso di vedere shebang sbagliate, come #! /usr/bin/env python3.

Come si comporta il launcher py quando gli chiedete di eseguire uno script che inizia con una di queste shebang?

  • In primo luogo, un py "versionato" (py -3 test.py, per esempio) ignora sempre la shebang, e sceglie sempre l'interprete Python di sistema (perfino quando siete dentro un venv, come abbiamo visto).
  • Anche python test.py ignora sempre la shebang: sceglie comunque il primo interprete Python che incontra nella path di sistema (e quindi l'interprete del venv, se siete dentro un venv).
  • Invece, un py "non versionato" (py test.py) tiene in considerazione la shebang dello script, se esiste (ovviamente, se non esiste si comporta come abbiamo visto finora). Più precisamente:
    • se trova una shebang "versionata" di qualsiasi tipo, sceglie l'interprete Python di sistema suggerito dalla shebang. Questo, anche se siete dentro un venv, e anche se la shebang è del tipo "env pythonX.Y" (che peraltro, come abbiamo detto, a rigore è sbagliata).
    • se trova una shebang "non versionata" e non-env, sceglie sempre il Python 2 di sistema, se disponibile. Questo, anche se siete dentro un venv. Questo lascia davvero un po' confusi, ma si tratta della convenzione Linux a cui anche il launcher py cerca di conformarsi.
    • infine, se trova la shebang #! /usr/bin/env python, sceglie il Python del venv, se siete dentro un venv; altrimenti, sceglie ancora Python 2 per uniformarsi alla convenzione Linux.

Tutto questo è un po' disorientante. Potete fare delle prove, comunque: aggiungete al vostro script test.py diversi tipi di shebang, e provate ad avviarlo in modi diversi (ma soprattutto con py test.py), fuori e dentro un venv.

Riassunto: come usare le shebang?

  • Se vi sembra tutto troppo complicato, semplicemente non usatele.
  • Se il vostro script, come di solito avviene, è pensato per essere eseguito in un venv, allora usate #! /usr/bin/env python (senza numeri di versione), e avviatelo con py test.py dentro il vostro venv.
  • se per eseguire il vostro script basta la sola libreria standard, allora sarebbe corretto non usare la shebang con env. Siete liberi di usare !# /usr/bin/python oppure #! python, ed eventualmente in una forma "versionata" (#! python3, per esempio). Per avviare lo script, usate sempre py test.py, che in questo caso sceglierà l'interprete Python di sistema. Attenzione, tuttavia: se usate queste shebang in una forma "non-versionata", sappiate che py test.py preferirà Python 2 (cosa che anche su Linux ormai sembra un po' superata...). Per questo vi conviene "versionare" la shebang.

Tutto sommato, non è poi troppo difficile.

Le dichiarazioni di encoding.

In primo luogo, dovreste avere almeno una discreta conoscenza di cos'è Unicode e cosa sono gli encoding: in caso contrario vi conviene informarvi subito sull'argomento.

Detto questo, una dichiarazione di encoding può (e deve, in certi casi) essere aggiunta in testa a uno script Python. Una dichiarazione di encoding deve stare nella prima riga dello script, se manca la shebang. Altrimenti, deve stare nella seconda riga dello script, immediatamente dopo la shebang. La dichiarazione di encoding ha la forma:

# -*- coding: <encoding> -*-

dove al posto di <encoding> dovete mettere il nome dell'encoding preferito, per esempio: # -*- coding: utf-8 -*-. (Molti encoding hanno degli alias che Python non ha problemi a riconoscere: utf-8, utf8, UTF-8 etc. vanno bene).

Prima di chiedervi quando è necessario inserire una dichiarazione di encoding, dovete tenere a mente la regola d'oro: nei vostri script Python, limitatevi a usare il set di caratteri ASCII. Fin quando usate solo ASCII, potete rimandare una comprensione più approfondita di Unicode e degli encoding. Ma soprattutto, questa è ancora la convenzione più comune tra i programmatori. Anche se è certamente possibile scrivere codice Python con caratteri "strani" (non-ASCII, per dirlo in modo più tecnico), i programmatori tendono a evitarlo il più possibile.

Questo ci porta a una importante questione di stile. Ciò che manca al set ASCII, dal nostro punto di vista, sono i caratteri accentati tipici dell'Italiano. Quindi potrebbe essere difficile scrivere codice in Italiano usando solo ASCII. Ma ecco il punto: il codice dovrebbe sempre essere scritto in Inglese, la lingua franca nel mondo della programmazione. Se non potete fare a meno di usare l'Italiano nonostante tutto, come minimo dovreste scrivere in Inglese i nomi delle variabili, e tutto ciò che è effettivamente "codice". Usate l'Italiano solo ed esclusivamente per le note e le docstring. Questo almeno vi consentirà in futuro di tradurre in Inglese i vostri script senza dover cambiare il codice vero e proprio. Se usate l'Italiano per note e documentazione, allora limitatevi comunque al set ASCII, con il vecchio trucco di sostituire gli accenti con gli apostrofi (perche' invece di perché, etc.). L'ultima cosa che volete è introdurre ulteriori complicazioni solo per il piccolo gusto estetico di vedere gli accenti nei commenti al codice.

Detto questo, occasionalmente potreste avere davvero bisogno di introdurre nel codice qualche carattere non-ASCII. Per esempio, delle stringhe di testo che devono essere mostrate all'utente, e quindi devono essere "giuste" con gli accenti e tutto il resto. A dire il vero, i programmatori bravi evitano anche in questi casi di uscire dal set ASCII, per esempio mettendo tutte queste stringhe in qualche tipo di risorsa esterna (un file di testo, un database...) da caricare dinamicamente, invece che inserirle direttamente nel codice dello script. Ma insomma, questo può essere troppo faticoso per le situazioni più semplici, e non è comunque un reato inserire un testo non-ASCII in uno script Python.

Se volete o dovete uscire dalla zona sicura di ASCII, è importante sapere in primo luogo che Python ha il concetto di "encoding di default" per gli script. L'encoding di default per Python 2 è ASCII, mentre l'encoding di default per Python 3 è UTF-8. Se il vostro script non usa l'encoding di default (per la versione di Python per cui è concepito), allora è necessario inserire una dichiarazione di encoding all'inizio dello script. La dichiarazione di encoding non è necessaria se lo script rispetta l'encoding di default. Anzi, in questo caso la dichiarazione di encoding non dovrebbe essere indicata, secondo la guida di stile ufficiale di Python.

Che cosa vuol dire che uno script "usa" un encoding? Che il vostro editor salva fisicamente il file utilizzando quel particolare encoding. Oggi, praticamente tutti gli editor "da programmatori" salvano i file in UTF-8 di default. In ogni caso, è fondamentale imparare subito a capire come si impostano le preferenze dell'editor, imparare come si fa a vedere se l'editor sta usando per qualche motivo un encoding differente, come si cambia l'encoding, etc. Per esempio, il Blocco Note che avete usato fino a questo momento salva i file con l'encoding cp-1252, e quindi non in UTF-8. Naturalmente non è l'unica ragione per cui non bisogna mai usare il Blocco Note per programmare, ma è già una ragione sufficiente.

Vediamo come si applica tutto questo al caso di Python 3. Se il vostro script è per Python 3, usate sempre UTF-8 come encoding (che del resto dovrebbe essere quello predefinito del vostro editor). Non c'è ragione, ormai, per usare un encoding diverso. Anche se vi limitate al set di caratteri ASCII (come dovreste), salvate comunque come UTF-8: è più una questione di forma che di sostanza perché ASCII è pur sempre un sub-set di UTF-8. Usando UTF-8, non dovete inserire dichiarazioni di encoding all'inizio del file.

Vediamo invece il caso di Python 2. Anche in questo caso, impostate il vostro editor per usare UTF-8, e salvate i file in UTF-8. Dovete fare attenzione però: se poi effettivamente nel vostro script usate anche caratteri non-ASCII, allora dovete aggiungere una dichiarazione di encoding all'inizio dello script.

Da quanto detto finora, dovrebbe essere chiaro che una dichiarazione di encoding non è, di per sé, una garanzia che il file sia effettivamente salvato con quell'encoding. Sta a voi assicurarvi che il vostro editor faccia la cosa giusta.

La dichiarazione di encoding, in ogni caso, vale solo per lo script a cui si riferisce. Se lo script accede a dati esterni (un database, un file di testo, l'input della shell...), la dichiarazione di encoding dello script non garantisce anche per questi dati, ovviamente. Dovreste conoscere l'encoding di tutti i dati esterni a cui volete accedere: informatevi sulle specifiche del provider di questi dati (per esempio, quasi tutti gli engine di database moderni restituiscono i dati in UTF-8; lo standard input della shell cmd.exe di Windows utilizza CP850, almeno nella configurazione italiana; etc.). Python ha degli strumenti per convertire gli encoding, naturalmente: per saperne di più potete partire dall'Unicode How-To nella documentazione ufficiale.

Parte quinta: struttura di un progetto Python.

Abbiamo concluso la nostra rassegna delle cose essenziali da sapere per installare e usare Python su Windows. Ci occupiamo adesso di alcuni aspetti più secondari, opzionali e anche soggetti ai gusti personali di ciascuno. Cominciamo con alcuni consigli su come strutturare un progetto Python.

Il meccanismo degli import in Python.

Come è possibile intuire dagli esempi che abbiamo fatto finora, l'istruzione import serve per "importare" e quindi rendere utilizzabile un modulo (ossia uno script, un file .py, diciamo) nel vostro codice Python (ossia nel vostro modulo, nel vostro file .py, diciamo). Il nome che importate può corrispondere a qualsiasi cosa: un semplice script costituito da un modulo soltanto, o un largo framework composto da package e subpackage e decine di moduli.

Quando gli chiedete di importare "qualcosa", Python compie una ricerca per trovare "qualcosa" che corrisponde al nome che gli avete chiesto: se non trova nulla, alla fine restituisce un errore ModuleNotFoundError: No module named .... La strategia di ricerca dei nomi da importare è piuttosto complessa e non è questa la sede per spiegarla nel dettaglio: la documentazione ufficiale è molto chiara in merito.

Tra i posti dove Python cerca i moduli (o i package) da importare, c'è naturalmente la libreria standard (la directory .../Lib/ della sua installazione) e quindi anche i pacchetti esterni installati con Pip (che si trovano di solito in .../Lib/site-packages). Infine, Python cerca anche in ., ovvero nella stessa directory in cui si trova il modulo che richiede l'import.

In altre parole, se avete due moduli a.py e b.py nella stessa directory, nel modulo a.py potete tranquillamente scrivere import b: Python lo troverà cercando in . (se poi la directory è un package, allora Python cercherà anche nelle sotto-directory: ma questo è un argomento più avanzato).

Allo stesso modo, se vi portate con la shell nella directory in cui stanno a.py e b.py, e aprite l'interprete interattivo Python (con py -3 per esempio), allora potete importare sia import a sia import b.

Ci sono diversi modi in cui potete modificare e personalizzare il meccanismo degli import di Python. In genere si tratta di tecniche avanzate, ma una è piuttosto popolare: potete impostare la variabile di ambiente PYTHONPATH. Questa variabile può contenere un elenco di path (separate da punto-e-virgola come di consueto) dove Python si impegna a cercare i moduli da importare. Per esempio, supponiamo che abbiate creato un modulo d:/test/a.py: potete seguire questa sessione della shell:

> :: assicuriamoci di NON essere in d:/test...
> cd d:/
D:\ > py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import a  # non funziona perche' non siamo in d:/test
(...)
ModuleNotFoundError: No module named 'a'
>>> exit()
D:\ > set PYTHONPATH=d:\test
D:\ > py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import a  # adesso funziona perche' guarda anche in PYTHONPATH
>>>

Lo stesso effetto, da "dentro" il codice Python, si può ottenere manipolando la variabile sys.path (che è una semplice lista Python):

D:\ > :: cancelliamo PYTHONPATH...
D:\ > set PYTHONPATH=
D:\ > py
Python 3.7.0 ([etc]) on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import a
(...)
ModuleNotFoundError: No module named 'a'
>>> import sys
>>> sys.path.append('d:/test')
>>> import a  # adesso funziona
>>>

Anche se è possibile modificare in questo modo il meccanismo di import di Python, in genere non bisognerebbe farlo. Se il codice per funzionare dipende da impostazioni specifiche del vostro ambiente di lavoro (per esempio PYTHONPATH), allora non funzionerà per nessun altro.

Come gestire il proprio codice Python.

Capito almeno in parte come funziona import, possiamo adesso rispondere alla domanda che spesso si pone chi inizia a programmare in Python: dove dovrei mettere il codice che scrivo?

In primo luogo, sicuramente non bisogna mettere i propri script nella installazione di Python (in .../Lib/ o .../Lib/site-packages per esempio), e neppure in un venv. In particolare, come abbiamo visto un venv dovrebbe essere ri-creabile solo a partire da un requirements.txt: quindi dovrebbe contenere solo Python stesso, la sua libreria standard e tutti i pacchetti installati con Pip.

Potete mettere i vostri script... dove preferite. Una buona idea probabilmente è metterli in una directory apposita, per esempio %USERPROFILE%/python_scripts o magari anche solo d:/scripts, come preferite. Questo vale per gli script stand-alone (composti da un solo modulo).

Un progetto Python più grande, composto da due o più moduli, dovrebbe sempre stare in una sua directory riservata (eventualmente potete renderla un package Python con l'aggiunta di un __init__.py, e aggiungere altre sub-directory/sub-package... ma sono argomenti avanzati). La directory di un progetto dovrebbe contenere solo ed esclusivamente materiale relativo a quel progetto: codice Python, documentazione, varie informazioni e così via. Vedremo tra poco come conviene strutturare un progetto Python. Per comodità, potete raccogliere tutte le directory/progetti in un solo posto: potrebbe essere %USERPROFILE%/python_projects, o anche solo d:/repos, come preferite ("repos" per "repository", anche perché spesso vorrete monitorare i vostri progetti con un version control system come Git: ne parliamo tra poco).

E come fate, se volete usare (e quindi importare) uno dei vostri script, magari uno dei vostri progetti, dentro un altro script o un altro progetto? Ecco, questo a rigore non si dovrebbe mai fare. Se due o più moduli appartengono allo stesso progetto, allora vivono nella stessa directory e sono quindi liberamente importabili tra loro. Ma non si dovrebbe mai importare un modulo "estraneo" al progetto, collocato in un posto "qualsiasi". Più precisamente: un modulo dovrebbe importare solo (a) i moduli della libreria standard, (b) i moduli dei pacchetti esterni installati con Pip, e (c) gli altri moduli dello stesso progetto/directory.

Di conseguenza, se avete scritto un progetto "A" (o anche solo un modulo stand-alone) e volete usarlo (importarlo) in un altro progetto "B", il modo corretto di procedere sarebbe di pacchettizzare il progetto "A" così da renderlo installabile con Pip. Non è necessario arrivare fino al punto di caricare fisicamente il pacchetto su PyPI: bisognerebbe però creare una wheel del progetto "A" e poi installarla con Pip nel venv del progetto "B". La guida ufficiale spiega nel dettaglio come si fa. Beninteso, se poi distribuite ad altri il vostro progetto "B" senza mai aver pubblicato (su PyPI o altrove) anche il progetto "A", allora chi usa il vostro progetto avrà qualche prevedibile problema. Ma questo è un altro discorso.

S'intende che, se avete seguito fino a questo punto, avete già capito la scorciatoia per evitare tutto questo: basta settare PYTHONPATH in modo opportuno per far sì che Python ricerchi i moduli da importare anche in directory arbitrarie. Per esempio, se includete d:/scripts nella PYTHONPATH, allora qualsiasi vostro progetto potrà importare tutti i moduli contenuti in d:/scripts, senza bisogno di pacchettizzarli e installarli con Pip. Capite però anche che questa scorciatoia può funzionare solo per voi. In generale, non è la cosa giusta da fare.

Struttura di un progetto Python.

Ci soffermiamo ora brevemente su come bisognerebbe organizzare un progetto Python ovvero, fisicamente, la directory che contiene tutti i file relativi al progetto. Ci sono molte guide, template, coding styles, suggerimenti di vario tipo in merito, e molti dettagli dipendono dalle abitudini di ciascuno, dai tool di sviluppo utilizzati, etc. Inoltre, i framework complessi come Django hanno le loro peculiariarità e le loro raccomandazioni specifiche.

Questo è un template molto generico che potete adottare:

project -
         |- project -
         |           |- __init.py__
         |           |- (moduli Python del progetto)
         |           |
         |           |- tests -
         |                     |- __init.py__
         |                     |- test_*.py (moduli di test)
         |
         |- docs -
         |        |- conf.py
         |        |- index.rst
         |        |- (file .rst della documentazione)
         |
         |- README.rst
         |- requirements.txt
         |- (LICENSE, AUTHORS... meta-informazioni)
         |- (.gitignore... file necessari ai tool)
         |- setup.py

In primo luogo, come già detto ogni progetto dovrebbe avere una sua directory, che avrà il nome del progetto: deve essere un nome corto ma significativo (quindi non project, naturalmente!), e per convenzione è tutto minuscolo, senza underscore.

Dentro la directory-base c'è un'altra directory con lo stesso nome, dentro cui mettete i moduli Python che effettivamente compongono il progetto. Questa struttura (project/project/<vari file py>) permette di tenere separati nella directory-base tutti i file di meta-informazione necessari (documentazione etc., come vedremo).

La directory "interna" (project/project) è destinata al codice: in genere si preferisce rendere questa directory un package Python, e pertanto si include anche un file __init__.py (che in genere è vuoto: se non sapete che cosa sono i package, dovreste leggervi la documentazione in merito). Se il vostro progetto è un package, è possibile strutturarlo ulteriormente in sub-packages (che fisicamente sono delle sub-directory di project/project, ciascuno con il suo __init__.py). Ma non è obbligatorio usare i package: potete benissimo limitarvi a riempire project/project con i moduli Python che compongono il vostro progetto, senza __init__.py. Se poi il vostro progetto si compone di un solo file, allora non ha molto senso neppure usare la directory interna project/project: potete mettere il vostro script direttamente nella directory-base project.

Nella directory interna project/project trova spazio una sub-directory project/project/tests che contiene i moduli dei test del vostro progetto. Gli "unit test" (e altri tipi di test) in Python sono praticamente un obbligo per ogni progetto serio: se non sapete nulla sull'argomento, potete iniziare dalla documentazione standard relativa. Per convenzione, i moduli dei test hanno un nome che inizia per test_. Se usate questa struttura, allora dovete usare i package, e quindi deve esserci sia project/project/__init__.py sia project/project/tests/__init__.py. Se non volete usare i package, allora non potete mettere i test in una sub-directory: potete metterli direttamente in project/project insieme al resto del codice. I moduli dei test si riconosceranno perché iniziano per test_.

Risaliamo alla directory principale project, e notiamo che contiene una sub-directory project/docs con la documentazione relativa al vostro progetto. Documentare bene il codice è un punto d'onore di ogni sviluppatore Python: nessuno vorrà avere a che fare con il vostro codice, se non è documentato. In teoria, siete liberi di decidere il formato, le strategie e gli strumenti per la vostra documentazione. In pratica però Sphinx è lo strumento più utilizzato nel mondo Python (anche per la documentazione ufficiale di Python stesso). Sphinx è un tool che genera diversi tipi di output (html, latex, etc.) a partire da testi scritti in reStructuredText. Nella vostra directory di documentazione project/docs non dovete includere l'output finale, ma solo i documenti reStructuredText (con estensione .rst) che servono a Sphinx per generare l'output, a partire da index.rst. In questo modo chiunque può generare l'output della vostra documentazione utilizzando il formato e il template di sua preferenza. Un file conf.py contiene i parametri necessari per Sphinx (leggete la documentazione per i dettagli).

Naturalmente non siete obbligati a usare Sphinx per la documentazione. Potete usare altri strumenti, mettere in project/docs dei semplici file di testo, o qualsiasi cosa volete: l'importante è che il progetto sia documentato.

La directory-base project contiene inoltre un numero variabile di file di meta-informazioni sul progetto. È praticamente obbligatorio un README (scritto così, senza estensioni; oppure README.txt o README.rst se è in reStructuredText, o README.md se è in Markdown, etc.). Il README contiene le informazioni essenziali, e dovrebbe essere scritto in Inglese (o come minimo avere una introduzione corta in Inglese all'inizio, se proprio non potete rinunciare all'Italiano). Un file LICENSE contiene il testo della licenza con cui volete distribuire il progetto. Non è necessario inserirlo però: se la licenza è standard e molto nota, basta un richiamo all'interno dei vostri moduli, e/o nel README. Altri file di meta-informazione comuni sono AUTHORS, CONTRIBUTORS, NEWS, history... tutti senza estensione o con estensioni variabili a seconda del formato.

Ci potrebbe poi essere un numero variabile di file (eventualmente auto-generati) necessari ai diversi tool di sviluppo che utilizzate. Per esempio, se usate Git per il controllo di versione, allora avrete una directory nascosta .git e probabilmente anche due file nascosti .gitconfig e .gitignore. Anche il vostro editor potrebbe appoggiarsi ad alcuni file nascosti nella directory-base per leggere delle impostazioni di configurazione.

Abbiamo già imparato a conoscere requirements.txt, che elenca i pacchetti che bisogna installare per far funzionare il vostro progetto in un virtual environment Python. Infine setup.py contiene le istruzioni necessarie a rendere il vostro progetto installabile con Pip (e quindi caricabile e distribuibile su PyPI): è un file essenziale se volete rendere pubblico il vostro lavoro. Per saperne di più su setup.py e tutte le operazioni necessarie, potete partire dalla documentazione standard.

Numeri di versione.

Assegnare un numero di versione a un progetto Python è importante, e occorre saperlo fare bene. Se distribuite il vostro progetto su PyPI, ogni volta che caricate degli aggiornamenti il numero di versione deve cambiare. Se il vostro progetto è su GitHub (o analogo), allora chiunque può clonarlo e usarlo anche in corrispondenza di commit intermedi tra due versioni: questo non è un problema, e non dovete certo modificare il numero di versione a ogni commit che fate. Tuttavia, deve essere ben chiaro a quali commit corrisponde un nuovo numero di versione (di solito, questo si ottiene taggando i commit) in modo che sia possibile clonare una versione ben precisa.

Il mondo Python ha adottato da tempo uno standard preciso per i numeri di versione, descritto nel dettaglio nella PEP 440. Detto in breve, si tratta del popolare schema "a tre numeri": un numero di "major version", uno di "minor version" e uno di "micro version" (o "bugfix release"). Per convenzione, dovreste sempre incrementare il primo numero ("major version") quando introducete delle modifiche non retrocompatibili con il codice precedente. Potete incrementare solo il secondo numero quando introducete modifiche retrocompatibili e/o aggiungete funzionalità; è tollerabile qualche piccolo cambiamento non retrocompatibile anche tra una versione minore e l'altra. Infine, dovete incrementare solo il terzo numero quando non avete introdotto nessuna modifica che riguarda l'utente finale (nessun cambiamento di API, in altre parole), ma vi siete limitati a correggere errori e/o implementare altri miglioramenti nel codice (prestazioni, documentazione, etc.). La PEP 440 regola anche l'utilizzo di codici per indicare versioni alfa, beta, candidate, pre- e post- release, etc.

È utile pubblicare l'elenco di tutti i cambiamenti apportati tra una versione e la successiva. Se usate Git o un altro sistema per il controllo di versione, e se la vostra strategia di commit è corretta, spesso il log di Git è tutto ciò che vi serve per questo scopo.

Manuale di stile e controllo automatico dello stile.

Il manuale di stile ufficiale di Python è la PEP 8 che bisogna leggere e conoscere a fondo. I programmatori Python sono molto sensibili sull'argomento, e se volete far vedere il vostro codice è meglio seguire sempre la PEP 8. Molti grandi progetti hanno inoltre un loro manuale di stile interno: se decidete di collaborare con questi, è ovviamente necessario conformarsi.

Il processo di rilevazione automatica dei potenziali errori nel vostro codice e dei potenziali difetti di stile si chiama linting. Esistono diversi linter che fanno un ottimo lavoro nel segnalarvi dove il vostro codice non è conforme alla PEP 8. Il più semplice è Pep8, ma ci sono opzioni più evolute come PyLint. Sono pacchetti che si installano normalmente con Pip, e si possono usare dalla riga di comando della shell. Ve detto però che molti editor offrono qualche tipo di integrazione con uno o più linter: se l'editor trova il linter installato, può usarlo per segnalare automaticamente i problemi con colori o codici differenti. Parleremo più diffusamente degli editor e della loro configurazione tra poco.

Come abbiamo già detto, il vostro linter appartiene a quella categoria di pacchetti "ausiliari" che non è sbagliato installare globalmente, e rendere eventualmente accessibili ai venv dei progetti con l'opzione --system-site-packages al momento di creare il venv.

Parte sesta: avviare con il doppio clic.

Dopo aver capito, almeno a grandi linee, come funzionano gli import in Python, dobbiamo tornare sull'argomento "doppio clic". Abbiamo già detto che gli script Python si invocano dalla shell e non facendo doppio clic sull'icona del file corrispondente - e lo confermiamo qui ancora una volta.

Tuttavia, il desiderio di trattare uno script Python come di solito si "avvia un programma" è comprensibile: ripetiamo (ancora!) che questo a rigore è un problema di pacchettizzazione e distribuzione del programma finito. Ci sono strumenti che vi consentono di generare degli eseguibili veri e propri, pronti per la distribuzione, che naturalmente si possono avviare con il doppio clic. Ne accenniamo più in là. Se volete il doppio clic, allora pacchettizzate il vostro script.

E tuttavia... il desiderio resta comunque! Può capitare di distribuire un "programma" (ovvero, destinato all'utente finale: non una "libreria", quindi) non pacchettizzato, o semplicemente di volerlo eseguire col doppio clic sul nostro computer per noi stessi, senza perdere tempo a pacchettizzarlo. In questo caso, tuttavia, potreste incontrare due famiglie di problemi: quelli legati alla directory di lavoro e alle path relative, se il vostro script deve accedere a risorse esterne come file o database; e quelli legati alle differenti versioni di Python e ai venv necessari.

Il problema con il doppio clic.

Per cominciare, create uno script e mettetelo, per esempio, in d:/test:

# d:/test/main.py

import os
print("directory corrente:", os.getcwd()) # stampa la directory corrente
try:  
    import foo  # prova a importare d:/test/foo.py
    print('"foo.py" importato correttamente')
except ImportError:
    print('"foo.py" non importato!!')
try:
    open('foo.txt').close() # prova ad aprire foo.txt
    print('"foo.txt" aperto correttamente')
except IOError:
    print('"foo.txt" non aperto!!')
input('Premi "invio" per terminare') # aspetta senza uscire subito

Poi mettete nella stessa directory un altro script, che può anche essere un semplice file vuoto, d:/test/foo.py. Infine, create anche un file di testo vuoto e chiamatelo d:/test/foo.txt.

Anche se non avete ancora cominciato a studiare Python, il significato del codice dovrebbe essere chiaro: proviamo a importare un modulo foo.py, e poi ad accedere a una risorsa esterna (in questo caso un semplice file di testo). Notate che identifichiamo la risorsa usando una path relativa foo.txt (ovvero, ./foo.txt) invece che la path assoluta d:/test/foo.txt.

Adesso facciamo qualche esperimento. Per prima cosa aprite una shell, e portatevi in d:/test

> cd d:/test
D:\test > py main.py
directory corrente: d:\test
"foo.py" importato correttamente
"foo.txt" aperto correttamente
Premi "invio" per terminare
D:\test > 

Come vedete, la directory corrente della shell al momento di invocare lo script viene passata a Python. Non ci sono problemi per l'import di foo.py, perché come sappiamo Python finisce per trovare il modulo cercando nella directory . (che è relativa alla posizione dell'entry-point main.py che abbiamo invocato). Non ci sono problemi neppure per l'apertura di foo.txt, che viene trovato alla sua path (./foo.txt) relativa alla directory corrente d:/test.

Adesso invece portiamoci in una directory diversa da d:/test e ripetiamo l'esperimento:

> :: assicuriamoci di NON essere in d:/test...
> cd d:/
D:\ > py d:/test/main.py
directory corrente: d:\
"foo.py" importato correttamente
"foo.txt" non aperto!!
Premi "invio" per terminare
D:\ >

In questo caso l'import va ancora a buon fine come prima, ma l'apertura del file è invece compromessa. Infatti adesso la directory corrente è d:/, ma non esiste nessun file d:/foo.txt! In effetti, occorre sempre ricordarsi che gli import sono relativi alla posizione dello script eseguito, ma le path delle risorse esterne sono relative alla directory corrente passata a Python al momento dell'invocazione.

Se adesso proviamo ad avviare lo script con il doppio clic, scopriamo che la directory corrente impostata da Windows è quella del file stesso, ovvero d:/test: questo garantisce la corretta apertura del file.

Infine, possiamo verificare che anche il doppio clic su un collegamento (soft link) allo script funziona come cliccare sul file originale: ovvero, la directory corrente resta quella del file originale, non quella del link. Il collegamento però offre una possibilità in più: se fate clic con il pulsante destro, scegliete "Proprietà" e poi la scheda "Collegamento", nella casella "Da:" potete impostare manualmente la directory corrente da passare.

Il problema con i batch file.

Talvota capita di voler invocare uno script Python attraverso un batch file (un file con estensione .bat). In questo caso però sappiate che la directory corrente passata a Python sarà quella del file batch, non quella del file dello script.

Potete verificarlo facilmente creando un file batch che contiene semplicemente questo:

REM test.bat
py d:/test/main.py

Se adesso mettete questo file in una directory qualsiasi (per esempio il desktop) e ci fate doppio clic sopra, vedrete che l'apertura del file fallisce, perché la directory corrente non è quella giusta.

Potete naturalmente impostare la directory corrente prima di avviare Python:

REM test.bat
d:
CD d:/test
py main.py

Impostare la directory corrente con Python.

In generale, lo script Python invocato nel modo "giusto" dovrebbe passare a Python la directory corrente del file dello script. Tuttavia, non potete aspettarvi che questo sia sempre vero (e anzi, talvolta è perfino preferibile che non sia così). Di conseguenza, ogni volta che volete accedere a una risorsa esterna (un file, un database...) localizzata con una path relativa, non potete essere sicuri che Python risolverà la path nel modo voluto.

Una soluzione sarebbe identificare le risorse esterne solo per mezzo di path assolute, ma chiaramente questo non va bene, perché sacrifica completamente la portabilità del vostro codice.

È però possibile impostare la directory corrente anche "da dentro" lo script Python. Modificate main.py in modo che all'inzio abbia queste righe:

# d:/test/main.py

import os, os.path
os.chdir(os.path.abspath(os.path.dirname(__file__)))
# etc. etc.

Qui, os.chdir vuol dire "imposta la directory corrente"; os.path.abspath significa "la path assoluta di..."; os.path.dirname è "la directory di..."; la variabile __file__ conserva il nome del file dello script. Se adesso riprovate tutti gli esperimenti fatti fin qui, noterete che la directory corrente resta sempre quella del file, anche se cercate di passare qualcos'altro dalla shell, o da un file batch, o con le impostazioni di un collegamento.

Se volete usare questa tecnica, vi conviene impostare la directory corrente molto presto nel vostro script: sicuramente, prima di accedere a qualsiasi risorsa esterna.

Se lo script ha bisogno di un venv.

Un altro ordine di problemi capita quando avete due o più versioni di Python installate, o magari quando il vostro script deve essere eseguito in un venv. In questi casi, naturalmente fare doppio clic lascia a Windows la scelta dell'eseguibile Python da invocare, e non sempre le cose andranno lisce.

In precedenza avevamo creato un venv di Python 3 in d:/venvs/test, e ci avevamo installato dentro il pacchetto Arrow. Se avete conservato quel venv (e in caso contrario, basta ricrerlo), potete verificare subito il problema. Modificate il nostro script main.py aggiungendo questo alla fine:

# d:/test/main.py

# ...
try:
    import arrow
    print('"Arrow" importato correttamente')
except ImportError:
    print('"Arrow" non importato!!')
input('Premi "invio" per terminare') # aspetta senza uscire subito

Se adesso eseguite lo script con il doppio clic, vedrete che Arrow non viene importato. Il motivo è semplice: Windows esegue lo script con il Python "di sistema", che non ha Arrow installato.

Per fare in modo che Windows selezioni l'interprete Python corretto (ovvero quello del venv) quando fate doppio clic sullo script, avete diverse opzioni.

In primo luogo, potete senz'altro attivare il venv da una shell prima di fare doppio clic. Ma si capisce che questo non avrebbe molto senso, visto che state appunto cercando di evitare di usare la shell.

In secondo luogo, potete impostare la shebang dello script indirizzandola verso l'interprete corretto:

#! d:/venvs/test/scripts/python.exe

# etc etc...

Questo funziona, ma non è una buona idea: legate il vostro codice a dettagli della configurazione specifica del vostro computer, e sacrificate la portabilità.

Terzo, potete usare un collegamento. Create un collegamento al vostro script main.py, apritene le "Proprietà" e nella scheda "Collegamento", casella "Destinazione" scrivete:

d:/venvs/test/scripts/python.exe d:/test/main.py

Accertatevi anche che la casella "Da:" contenga la path della directory corrente che volete passare a Python. Adesso, se fate doppio clic sul collegamento, Windows eseguirà lo script con l'interprete giusto. Questa soluzione è buona: non dovete toccare il vostro codice, e i dettagli di configurazione restano specificati in un collegamento che potete modificare separatamente.

Infine, quarto, potete usare un file batch in modo del tutto analogo:

REM test.bat
d:
CD d:/test
d:/venvs/test/scripts/python.exe main.py

Se preferite, potete usare il file batch per attivare il venv:

REM test.bat
REM ...
CALL d:/venvs/test/scripts/activate.bat
py main.py

O anche, siccome l'attivazione di un venv è in sostanza una manipolazione della path di sistema:

REM test.bat
REM ...
SET path=d:/venvs/test/scripts;%path%
py main.py

Usare un file batch è un'altra buona soluzione, che vi consente di separare dal codice Python i dettagli della vostra configurazione specifica. Il vantaggio di un file batch rispetto a un semplice collegamento "preparato", è che vi permette all'occorrenza di fare molte cose in più prima di avviare lo script Python. Per esempio potete impostare delle variabili d'ambiente, creare file e directory di lavoro, e in generale preparare l'esecuzione dello script senza inquinare il codice Python con dettagli specifici per la vostra configurazione.

Che cosa fare con l'output dello script.

Talvolta il vostro script produce un output che desiderate vedere nella shell: per esempio, in seguito a un print. Se invocate lo script dalla shell, questa resta aperta durante l'esecuzione. Ma se fate doppio clic, tipicamente la shell (la "finestrella nera", per capirci) si apre, esegue lo script, mostra l'output e poi si chiude: tutto questo avviene troppo rapidamente per permettervi di capirci qualcosa. Per esempio, se avete uno script così...

# d:/test/foo.py

print(2+2)

...e ci fate doppio clic sopra, non farete mai in tempo a vedere che per Python, effettivamente, 2+2 fa 4.

La soluzione standard è quella che abbiamo già adottato negli esempi precedenti: fare in modo che lo script termini con una richiesta di input per l'utente. In questo modo lo script si blocca (e la shell non si chiude!) finché l'utente non ha immesso l'input premendo invio. La funzione da usare è raw_input in Python 2, e input in Python 3:

# d:/test/foo.py

print(2+2)
input('Premi "invio" per terminare!')
# oppure raw_input('...') in Python 2

Che cosa fare in caso di errore.

Può capitare che lo script incontri un'eccezione non gestita (ovvero, non compresa in un blocco try/except), il che di solito corrisponde a una situazione di errore imprevisto. In questo caso, Python si arresta inaspettatamente dopo aver pubblicato sullo stream dello "standard error" il traceback dell'eccezione incontrata: naturalmente, lo "standard error" è diretto verso la shell, di solito. Questo significa che avete lo stesso problema di prima. Se avviate lo script dalla shell, tutto va bene: Python si arresta, ma la shell resta aperta e voi potete esaminare il traceback dell'errore incontrato e capire il problema. Ma se fate doppio clic, la shell si chiude immediatamente e voi restate senza informazioni.

Questa situazione non può essere risolta con un input finale, perché l'eccezione capiterà appunto prima che Python arrivi alla fine dello script:

# d:/test/foo.py

print(2+2)
try:
    print(1/0)  # eccezione gestita da un try/except
except ZeroDivisionError:
    print('Tutto bene... vado avanti!')
print(1/0) # OPS! eccezione non gestita!
input('Premi "invio" per terminare!')

Qui Python pubblicherà il risultato della prima istruzione (4) nello "standard output" (la shell). Poi incontrerà una eccezione gestita in un blocco try/except, scriverà un messaggio nello "standard output" e andrà avanti. Poi però incontrerà un'eccezione non gestita, e a questo punto pubblicherà lo stacktrace nello "standard error" (sempre la shell). Infine terminerà l'esecuzione dello script prematuramente, prima di arrivare all'input finale.

Certo, la verità è che, almeno in un software destinato all'utente finale, tutte le eccezioni dovrebbero essere previste e gestite. Un'eccezione non gestita è un baco. Ma appunto, anche i bachi succedono, e ci serve lo stacktrace dell'eccezione per poterli correggere. In fase di sviluppo di solito questo non è un problema perché voi avviate sempre lo script dalla shell. Ma un baco può capitare anche dopo, quando ormai considerate il vostro programma "finito" e volete avviarlo comodamente con il doppio clic.

La cosa peggiore è che un errore di questo tipo potrebbe capitare non solo all'interno del codice Python vero e proprio, ma anche a causa di una gestione sbagliata dell'ambiente di esecuzione. Per esempio, se facendo doppio clic avviate lo script con l'interprete sbagliato, Python potrebbe incontrare immediatamente degli ImportError (se magari non siete nel venv giusto), o addirittura dei SyntaxError (se state eseguendo lo script con una versione sbagliata di Python). Questo è il famigerato caso del "flash della finestrella nera": fate doppio clic, e tutto ciò che vedete è la finestra della shell che si apre per un istante e poi subito si chiude. La frustrazione cresce perché talvolta invece, eseguendo lo script dalla shell, tutto funziona (perché la shell è nel venv giusto, o seleziona la versione giusta di Python).

Ci sono diverse possibilità per risolvere questi problemi. Una idea valida, anche se un po' rozza, è re-direzionare lo stream dello "standard error" verso un file di log, invece che nella shell. In caso di errore, in seguito potete aprire il file e ispezionare lo stacktrace:

# d:/test/foo.py

import sys
sys.stderr = open('stderr.txt', 'a')
print(1/0)

Questo non è del tutto a prova di bomba, ma basta e avanza per i casi più comuni. In particolare, vi salva dalle eccezioni non gestite (come lo ZeroDivisionError qui sopra) e anche dagli ImportError iniziali dovuti all'interprete sbagliato. Naturalmente dovreste re-direzionare lo "standard error" molto presto nel vostro codice, e senz'altro prima del primo import che potrebbe fallire. Tenete conto però che questo trucco non può fare nulla contro eventuali SyntaxError che vengono rilevati da Python in fase di compilazione, e quindi prima che il vostro codice venga effettivamente eseguito. Possono esserci situazioni particolari in cui Python si interrompe prima di essere riuscito a completare la scrittura dello stracktrace nel file, e situazioni in cui il file stesso risulta mancante, corrotto, etc. Senza contare, naturalmente, i rari casi in cui lo stesso interprete Python (e non solo il vostro codice, quindi) può andare in crash.

Una possibilità analoga, ma più raffinata, è ricorrere a sys.excepthook: questa funzione contiene del codice da eseguire come ultima istanza, esclusivamente in caso di eccezione non gestita. Potete sovrascriverla e fare quello che desiderate in questa fase: in questo esempio noi scriviamo lo stacktrace nella shell e, invece di uscire immediatamente, blocchiamo lo script con il trucco che già conosciamo:

# d:/test/foo.py

import sys, traceback
def excepthook(exc_type, exc_value, exc_traceback):
    print("Ecco un'eccezione non gestita!!")
    traceback.print_exception(exc_type, exc_value, exc_traceback)
    input('Premi "invio" per terminare.')

sys.excepthook = excepthook

print(1/0)

Notate che, per la stessa ragione di prima, questo meccanismo non vi difende dai SyntaxError né dagli "hard crash" dell'interprete Python, e comunque andrebbe inserito molto in alto nel vostro codice. Usare sys.excepthook è comunque, in generale, un'idea migliore del semplice re-direzionamento dello "standard error". Nella vostra funzione potete usare un sistema di logging per conservare lo stacktrace dell'eccezione, emettere un messaggio di avviso per l'utente, prendervi il tempo chiudere le risorse rimaste aperte (connessioni al database...) ed eseguire altre operazioni di cleanup prima di terminare il programma. Fate solo attenzione, naturalmente, che queste operazioni non inneschino a loro volta altre eccezioni.

Infine, ricordate che tutti questi rimedi valgono solo a partire dal momento in cui il controllo passa all'interprete Python. Se fate qualche errore prima, per esempio nel file batch che avvia lo script, oppure se sbagliate a scrivere la path dell'interprete nelle impostazioni del collegamento... questi sono errori che non riguardano Python, e che dovete correggere per conto vostro.

Parte settima: tool per programmare.

Gli strumenti di lavoro del programmatore sono infiniti, e ciascuno nel tempo sviluppa le sue preferenze e le sue antipatie. In questa sezione elenchiamo solo alcuni strumenti indispensabili, o quasi.

ConEmu: console emulator.

Arrivati a questo punto, avrete ormai notato che la shell è uno strumento indispensabile e onnipresente per programmare (e non solo in Python). Avrete anche notato che la shell di Windows cmd.exe è particolarmente scomoda. Non potete fare a meno di un "console emulator", e ConEmu è il migliore in circolazione per Windows. ConEmu è un software complesso ma a voi basterà conoscere le basi. ConEmu è un manager in grado di gestire diverse shell contemporaneamente (cmd.exe, PowerShell, ma anche Git Bash come vedremo) e di offrire alcuni servizi aggiuntivi come font, colori, etc. Uno dei molti vantaggi di ConEmu è la facilità con cui potete aprire una shell in modalità "privilegiata" (ovvero con privilegi da amministratore), cosa che come abbiamo visto può tornare utile per installare pacchetti nel Python 3 di sistema, per settare variabili d'ambiente in modo permantente, etc.

È preferibile installare ConEmu nella sua versione potenziata Cmder, che oltre a ConEmu include anche Clink (che emula le funzionalità di GNU Readline, e offre shortcut aggiuntivi). L'installer di Cmder, volendo, comprende anche Git for Windows: è tuttavia preferibile installare Git separatamente, come vediamo qui di seguito.

Git: version control system.

Da qualche anno GitHub è diventato un modo molto popolare di pubblicare il proprio codice, condividerlo, cercare collaborazioni, farsi conoscere. Anche se non avete intenzione di aprire un account su GitHub, probabilmente vi conviene comunque usare un sistema di controllo di versione (VCS) per i vostri progetti, e Git è ormai di gran lunga il più popolare. Non è questa la sede per descrivere che cosa è e a cosa serve un VCS: la documentazione di Git fa un buon lavoro anche a spiegare la filosofia e le strategie d'uso più comuni.

Per installare Git su Windows, avete due possibilità. La prima è GitHub Desktop, una interfaccia grafica progettata per semplificare la gestione delle repository su GitHub, ma che si può usare anche solo in locale. È un software molto piacevole e intuitivo da usare, ma non è la nostra prima scelta. Dopo tutto, Git è nato come uno strumento di lavoro snello, che si governa con la shell: i comandi più comuni, poi, sono davvero semplici da usare. L'interfaccia grafica può sembrare più accattivante, ma alla fine appesantisce un po' l'uso di Git, tutto sommato senza buone ragioni. Inoltre molti editor ormai offrono qualche tipo di integrazione con Git, e quindi userete Git quasi sempre dal vostro editor.

Il nostro consiglio è invece di installare Git per Windows uno strumento più snello che comprende, oltre a Git, la shell Git Bash (un porting della nota shell Unix Bash), l'interfaccia grafica GitGui (abbastanza comoda da usare, se proprio volete restare lontani dalla shell) e il "commit viewer" GitK (utile per avere una rappresentazione grafica dell'albero dei commit, per esempio).

Al momento di installare Git per Windows, potete scegliere tra le numerose opzioni quelle che vi sembrano più opportune. Vi consigliamo in particolare di selezionare "Use Git from Git Bash only", dal momento che Git Bash è una shell molto più completa del solito cmd.exe (molti installano Git anche solo per avere Bash!), e vi conviene abituarvi ad usarla per tutte le vostre operazioni, e non solo quelle con Git. Quando poi si arriva alla scelta della console, è indifferente selezionare "Use Windows' default console window", oppure scegliere MinTTY: la verità è che comunque useremo Git Bash all'interno di ConEmu che abbiamo già installato, senza ricorrere né a cmd.exe né a MinTTY. Se però non avete ConEmu, allora usate senz'altro MinTTY. Infine, ricordatevi di selezionare "Enable Git Credential Manager" specialmente se avete intenzione di usare Git per collegarvi a un server come GitHub.

Completata l'installazione, potete usare GitGui per le operazioni sulle vostre repository Git, se preferite. Ma probabilmente la cosa più rapida è lavorare con Git Bash, con qualche occasionale sguardo a GitK. Vi conviene usare Git Bash all'interno di ConEmu, chiaramente. La cosa migliore è registrare un nuovo task in ConEmu ("Win+Alt+T", poi "Add default task") che potete chiamare "Bash" e dovrebbe avere un comando come:

"C:\Program Files\Git\bin\sh.exe" --login -i -new_console:d:"d:\repos"

Notate che è importante selezionare il corretto eseguibile ...\Git\bin\sh.exe, e assolutamente non git-bash.exe che avvia Bash in un terminale suo proprio (cmd.exe o MinTTY a seconda di cosa avete scelto installando Git). Come directory di partenza vi conviene scegliere la directory base dei vostri progetti (d:/repos nel nostro caso).

Una volta avviata la shell Bash, potete portarvi nella directory del progetto che vi interessa e dare il comando git init per creare lì una repository Git. Il prompt (master) vi indicherà a questo punto che siete nel branch di default master. Giocare con Git dalla shell a questo punto è facile. Provate per esempio:

(master) $ git checkout -b devel
Switched to a new branch 'devel'

(devel) $ touch README.rst LICENSE NEWS requirements.txt

(devel) $ git status
<...>

(devel) $ git add -A

(devel) $ git commit -m "initial"
<...>

(devel) $ gitk

Se invocate gitk mentre siete in una repository, aprite l'interfaccia grafica di GitK e potete vedere i vostri commit (naturalmente potete usare anche git log per questo).

Jupyter Notebook: shell interattiva.

L'interprete interattivo dei comandi Python (la shell con il caratteristico prompt >>>, per intenderci) è uno strumento essenziale non solo per le piccole necessità di tutti i giorni, ma anche quando siete immersi in un progetto "importante". La shell vi consente di provare rapidamente frammenti di codice, verificare la documentazione, importare ed eseguire interattivamente il codice che state scrivendo, e così via.

Non c'è niente di male nell'invocare l'interprete Python direttamente nella vostra shell, come abbiamo fatto finora: è il modo più rapido, e spesso è più che sufficiente. Tuttavia per le sessioni più lunghe e impegnative desiderate avere un'interfaccia migliore. Le opzioni non mancano, a partire da IDLE, la shell di default che trovate installata con Python. Potete avviare IDLE dai link del Menu Start, naturalmente. Ma forse a questo punto preferite usare la shell:

> py -m idlelib

In questo modo potete avviare le diverse IDLE "globali" (con py -2 -m idlelib, py -3 -m idlelib etc.) oppure, se siete all'interno di un venv, la IDLE del venv.

Un'altra opzione è costituita dal vostro editor. Molti editor evoluti offrono la possibilità di integrare una REPL per vari linguaggi di programmazione, tra cui naturalmente anche la shell di Python. In genere potete configurare la shell integrata per lavorare globalmente, oppure all'interno di un venv.

Tuttavia in questi anni si è progressivamente affermata una shell molto evoluta e ricca di opzioni: gli Jupyter Notebook (in precedenza noti come IPython Notebook) sono lo stato dell'arte, al punto che è riduttivo considerli solo delle shell. Jupyter è piuttosto un ambiente di sviluppo (IDE) interattivo, rivolto soprattutto alla comunità scientifica e alle applicazioni di data visualisation. Il sito è ricco di esempi e la documentazione è molto completa. Potete provare i notebook nel vostro browser senza installare nulla, se volete farvi un'idea.

Il sito ufficiale raccomanda di usare i notebook Jupyter installando Anaconda, una distribuzione di Python dedicata soprattutto all'ambito scientifico che comprende moltissimi pacchetti pre-installati tra cui, appunto, anche Jupyter. Ma non è assolutamente necessario installare Anaconda per usare i notebook Jupyter. Potete installare Jupyter semplicemente con Pip: pip install jupyter è tutto ciò che serve. Siccome Jupyter ha bisogno di moltissimi altri pacchetti, è consigliabile installarlo in un venv appositamente creato, per poterlo valutare senza impegno. Se vi piace, potete successivamente installarlo nel Python di sistema. Non è pensabile installarlo in ciascun venv di progetto, naturalmente: potete però renderlo disponibile ai venv con l'opzione --system-site-packages di cui abbiamo già parlato.

Una volta installato Jupyter, avete due opzioni principali per avviarlo. Potete invocare dalla shell jupyter console per aprire un notebook con l'interfaccia testuale direttamente nella shell. Oppure potete invocare jupyter notebook per aprire un notebook nel vostro browser, e sfruttare tutte le opzioni che vi offre l'interfaccia grafica. Le possibilità dei notebook Jupyter sono impressionanti: leggete la documentazione online per farvi un'idea.

Scegliere un editor.

Come abbiamo già avuto occasione di dire, non si può scrivere codice con il Blocco Note o (addirittura!) con Word. Dovete imparare a usare un editor "intelligente" di file di testo. La scelta di un editor dipende da mille fattori, è sempre molto personale, e la rete è piena di discussioni interminabili su qual è il "miglior editor". Ci limitiamo qui ad alcune considerazioni e suggerimenti molto generici.

In primo luogo, è sempre più difficile distinguere tra un "IDE" e un "editor". In teoria un IDE è un ambiente integrato che comprende, oltre all'editor vero e proprio, molti altri strumenti (debugger, compiler, code completion, integrazione con vari framework, version control system, e altro ancora); un editor d'altra parte è "solo" specializzato nella scrittura del codice, e offre funzionalità più mirate al codice in senso stretto, e non allo sviluppo di applicazioni in senso più ampio. In pratica però tutti gli editor più importanti possono essere ampliati con estensioni di vario tipo che aggiungono funzionalità, fino a trasformarli in veri e propri IDE. Di contro, è possibile disattivare molte funzionalità non necessarie di un IDE, fino a usarlo quasi come un editor. È vero comunque che un IDE tende a "imporsi di più" sul lavoro che fate: per sfruttarlo al meglio dovete accettare un po' di sovrastruttura necessaria. Un editor, per contro, di solito è più snello e non impone nessun particolare modo di lavorare. D'altra parte, gli IDE "all inclusive" possono essere più facili da usare e configurare; un editor invece potrebbe essere quasi inutilizzabile così com'è, e aver bisogno di un lungo processo di configurazione per lavorare come serve a voi.

Ma tutte le differenze sono opinabili, e per ogni generalizzazione ci sono sempre dieci contro-esempi. Scegliete con calma l'editor o l'IDE che si adatta di più al vostro modo di lavorare e al vostro gusto.

In primo luogo, il già menzionato IDLE comprende oltre alla shell interattiva anche un editor. In genere non sono molti quelli che continuano a usare IDLE dopo i primi esercizi. IDLE è inteso come ambiente di lavoro provvisorio e spartano per chi, dopo aver installato Python, desidera mettersi subito al lavoro. Anche se all'inizio potrebbe piacervi proprio per la sua semplicità, probabilmente è meglio investire fin da subito in un editor più completo, in grado di supportarvi mentre progredite nella vostra conoscenza di Python.

A parte IDLE, il primo editor che dovreste prendere in considerazione è Vim: è un editor concepito per girare direttamente nella shell, senza interfaccia grafica. È estremamente potente e flessibile, ed è l'editor preferito da molte "star" della programmazione. Ha una vasta e vocale "fan base" pronta a sostenere che sia il miglior editor possibile. La verità è che è anche un editor difficile da imparare e difficile da configurare. Si può scaricare e installare una versione dotata di interfaccia grafica (gui): ma nessuno sostiene che la gui di Vim sia competitiva con quelle dei moderni editor come Sublime Text o altri. Vim è fatto per essere usato nella shell, senza il mouse, i menu a tendina e le altre piacevolezze grafiche a cui siamo abituati. Molti programmatori però lavorano proprio in questo modo, senza mai uscire dalla shell (o meglio, dall'emulatore di terminale che comprende la shell). Se il vostro lavoro si svolge tutto o quasi nel terminale, allora probabilmente Vim è davvero il vostro editor (ma potreste voler dare un'occhiata anche a Emacs prima di fare una scelta definitiva).

Tuttavia, anche se Vim non è il vostro editor preferito, è comunque obbligatorio imparare e memorizzare almeno i pochi comandi fondamentali che vi permettono di aprire un file, apportare delle modifiche, salvare e uscire. Infatti ci sono alcune occasioni in cui Vim è davvero tutto quello che avete: per esempio se usate Git, quando dovete scrivere un messaggio di commit Git Bash apre Vim per voi (questa può essere una sorpresa... interessante, la prima volta che capita). Oppure, quando vi collegate a un server remoto con una connessione ssh, Vim è praticamente l'unica cosa che siete sicuri di trovare, e che funziona in una shell, se volete anche solo aprire e leggere un file. Infine va detto che Vim, con tutte le sue peculiarità, è comunque lo strumento più comodo quando dovete modificare al volo un file, senza bisogno di abbandonare la shell e aprire un editor separato.

Se avete installato Git for Windows e quindi Git Bash, avete già anche Vim. Portatevi in una directory in cui c'è un file di testo, e apritelo con Vim:

$ vim miofile.txt

...e adesso la domanda è: come faccio a uscire? Ecco perché occorre imparare almeno le basi di Vim! (Suggerimento: premete in sequenza <esc>:wq<invio> per salvare le modifiche e uscire, o <esc>:q!<invio> per uscire senza salvare).

Se preferite un editor grafico o un IDE, allora la scelta non manca. Il boss degli IDE è sicuramente Eclipse da usare con i tool specifici per Python di PyDev. Si tratta della "esperienza IDE" per definizione, completa e totalizzante, che integra e supporta ogni aspetto della vostra attività di programmatore. Il vantaggio è che non resta nulla o quasi che dovete cercare altrove. Lo svantaggio, probabilmente, è che vi sentirete un po' costretti a fare le cose solo in un certo modo. È davvero una questione di gusti, alla fine. Da un punto di vista tecnico, considerate solo che Eclipse/PyDev è esigente in termini di richieste di sistema: se amate programmare in treno tenendo il sub-notebook sulle ginocchia, allora Eclipse potrebbe non essere lo strumento giusto per voi.

Tra gli IDE "corposi", la principale alternativa a Eclipse/PyDev è PyCharm: sembra che in questi anni stia prendendo il sopravvento su Eclipse in termini di popolarità, quindi forse vorrete dare un'occhiata prima a questo. Un'alternativa ulteriore potrebbe essere WingIde (la cui versione free è tuttavia piuttosto limitata).

Parlando di IDE in Windows, non possiamo certo trascurare Visual Studio. La corazzata di casa Microsoft ha fatto negli ultimi anni due passi importanti che l'hanno resa competitiva anche al di fuori del mondo .Net e per la programmazione Python nello specifico: Visual Studio Community, una versione free dedicata espressamente al mondo dell'open source, e i Python Tools per Visual Studio, sviluppati dal Python Team di Microsoft (guidato da Steve Dower, che è anche l'esperto Windows tra i core developer di Python, e il responsabile delle Windows release di CPython). È difficile paragonare punto-a-punto Eclipse/PyDev e Visual Studio/Python Tools: sicuramente se siete interessati anche allo sviluppo .Net, allora Visual Studio dovrebbe essere lo strumento che fa per voi.

Se gli IDE vi sembrano troppo ingombranti e preferite un editor grafico più snello, allora davvero avete l'imbarazzo della scelta. Ce ne sono talmente tanti che spesso è solo una questione di mode passeggere: per esempio negli ultimi anni Atom e Brackets hanno preso quota; ma nel mondo Windows Notepad++ resta sempre uno dei più popolari.

Ma il primo della classe nel campo degli editor grafici è probabilmente Sublime Text: vanta una larga e attiva comunità di utenti, e una repository sterminata di add-on che coprono praticamente qualsiasi necessità. Sublime Text ha introdotto o reso popolari molti concetti innovativi come l'editing multi-cursore, che poi sono stati emulati dagli editor grafici più giovani. In effetti, editor come Atom o Brackets hanno un'aria... molto familiare per chi è abituato a Sublime Text. Un pregio ulteriore di Sublime Text è la sua notevole velocità e robustezza: è difficile vedere un crash o un rallentamento anche con file di notevoli dimensioni. In generale, Sublime Text è forse l'unico editor grafico che non fa storcere il naso neppure alla "vecchia scuola" degli hacker che usano Vim o Emacs. Il lato negativo è che è un po' difficile da configurare, e la sovrabbondanza di add-on rende complicato scegliere. Se volete usare Sublime Text per la programmazione Python, vi conviene prendere spunto da una guida come questa.

Prendiamo infine in considerazione Visual Studio Code, un editor di Microsoft ancora giovane, ma che è già cresciuto rapidamente e si è conquistato una sempre crescente quota di successo. Nonostante il nome, non ha niente a che vedere con Visual Studio. È basato sul motore Node.js Elektron, cosa che lo rende parente stretto di Atom; e come Atom, è evidententemente ispirato a Sublime Text. È tuttavia più veloce e stabile di Atom, e rispetto a Sublime Text sembra un po' meglio organizzato, più facile da usare. Chiaramente non può competere con Sublime Text in velocità e nella quantità di stili e add-on disponibili. Se siete programmatori esperti e avete già delle esigenze particolari, Sublime Text è ancora imbattibile (e forse lo resterà per molto tempo). Se state iniziando, Code potrebbe essere uno strumento interessante: relativamente stabile, veloce, facile da usare, in rapida crescita e con un buon supporto da parte di Microsoft. E in definitiva, una volta imparato Code è comunque molto facile passare poi a Sublime Text.

Aggiungiamo qualche indicazione su come usare Code per la programmazione Python. Con questo non intendiamo suggerire che Code sia l'editor migliore: è solo facile da impostare, e quindi adatto a una breve guida come questa, per dare l'idea di cosa più o meno occorre fare anche con gli altri editor. Prima di tutto, bisogna scaricare e installare Code. Fatto questo, occorre procurarsi l'estensione ufficiale per Python. Potete installarla direttamente da Code: cliccate sul pulsante "Extensions" nella barra a sinistra (o usate la shortcut Ctrl+Shift+x), cercate "Python" (per riconoscerla, ricordate che è distribuita dalla stessa Microsoft) e installate. Il manuale completo si trova qui.

Code ha la nozione di "spazio di lavoro" (workspace), che corrisponde a una directory: usate quindi "Open folder..." per aprire uno spazio di lavoro e il pulsante "Explorer" della barra a sinistra per vedere i file della directory. Potete regolare le impostazioni generali (File -> Preferences -> User settings...), e le impostazioni specifiche per lo spazio di lavoro (File -> Preferences -> Workspace settings...). Le impostazioni dello spazio di lavoro sovrascrivono le impostazioni generali: Code genera una directory nascosta .vscode e all'interno un file settings.json per registrare le impostazioni dello spazio di lavoro. Potete semplicemente copiare questo file da un progetto all'altro, se volete mantenere le stesse impostazioni in diversi progetti. Se non trova un settings.json nello spazio di lavoro (o se aprite semplicemente un file, e non una directory) allora Code usa solo le impostazioni generali.

Nell'elenco dei setting, un'attenzione particolare meritano le varie path. La path predefinita per l'interprete Python è "python.pythonPath": "python" che come già sappiamo punta al primo interprete che Windows trova nella path di sistema. Potete lasciare questa impostazione così com'è, oppure selezionare manualmente un venv "generico" in cui preferite installare i pacchetti di uso più comune. Impostate poi "python.venvPath" con la directory in cui risiedono i vostri venv (noi fin qui abbiamo usato "D:/envs). In questo modo Code mantiene un elenco di tutti i venv che avete creato, oltre a quelli che trova installati globalmente. Code vi mostra sempre quale interprete sta usando attualmente, nella barra di stato: se non è quello giusto, basta cliccarci sopra per sceglierne un altro. Una volta che Code lavora nel venv giusto per il vostro progetto, anche l'autocompletion funzionerà meglio, mostrandovi i suggerimenti dai pacchetti che avete installato nel venv.

Potete accedere a una shell Python senza bisogno di uscire da Code: aprite la palette dei comandi (shortcut Ctrl+Shift+P) e inserite "Python: Start REPL" (l'autocompletion vi aiuterà). Eccovi pronta una shell Python interattiva, che usa lo stesso interprete del vostro codice, e "vede" quindi gli stessi pacchetti installati.

Il linter predefinito è PyLint, ma potete configurarne altri (e anche più di uno). Chiaramente PyLint va installato, prima di poterlo usare: se Code non lo trova, si offre di istallarlo per voi. I messaggi di PyLint sono riassunti nella barra di stato: cliccate per avere un report più dettagliato. Code rispetta le impostazioni di PyLint per il filtraggio dei messaggi, se usate un file .pylintrc: vi rimandiamo alla guida per i dettagli.

Se avete installato Git, allora Code vi offre una discreta integrazione: il pulsante "Git" nella barra di sinistra vi consente di fare le operazioni più comuni (commit, push, pull...). La barra di stato mostra la branch attiva e vi permette di fare un checkout. Per altri comandi anche piuttosto comuni (tag, log...) dovete comunque usare la shell, ma tutto sommato potete gestire la maggior parte del vostro flusso di lavoro dall'interno dell'editor. Nei progetti dove non volete usare Git, vi conviene impostare "git.enabled": false nelle preferenze dello spazio di lavoro.

Code e Python for Visual Studio Code vi offrono molte altre opzioni relative a fattorizzazione, formattazione, unit test, debugging, integrazione con Jupyter. La guida spiega tutto nel dettaglio.

Font per programmatori.

Una delle prime cose che in genere si fanno dopo aver installato un editor, è configurare l'aspetto estetico. Non è solo per divertirsi con le impostazioni: dopo tutto, passerete parecchie ore a fissare la finestra del vostro editor, e non può essere una cosa sgradevole da fissare. Per esempio, molti programmatori preferiscono una combinazione di colori scura (come l'onnipresente Monokai o una delle sue varianti) perché la trovano più riposante per gli occhi.

La scelta più importante, tuttavia, è quella di un font con cui visualizzare il codice. Naturalmente non può essere un font a larghezza variabile come quelli usati di solito in tipografia: è necessario usare invece un font a larghezza fissa (stile "macchina da scrivere") per avere incolonnamenti esatti, vedere la lunghezza delle righe, etc. Tra i font a larghezza fissa, occorre scegliere quelli che permettono di distinguere bene alcuni caratteri simili: "zero" e "o maiuscola", "uno" e "elle minuscola", "punto e virgola" e "due punti", e così via. Per esempio se lo "zero" non è barrato, allora non è un font da programmatore, e così via.

Un altro fattore determinante per la scelta del font è la resa a diverse dimensioni, a seconda della geometria del vostro schermo. Qui occorre tener conto che, per regola, la riga non dovrebbe essere più lunga di 79 caratteri. Mantenendo la finestra dell'editor a tutto schermo, la dimensione "giusta" del font è quella che vi consente di avere tutta la riga visibile, lasciando spazio a destra e a sinistra per gli ulteriori elementi grafici previsti dall'editor (barre laterali, gutter, numeri di riga...). Siccome molti editor hanno elementi laterali ingombranti, un fattore di pregio per un font è la sua "compattezza" (una buona crenatura): la riga deve essere densa, ma restare ugualmente ben leggibile. In ogni caso, se il font non rende bene quando è regolato alla dimensione giusta per il vostro editor e il vostro schermo, è meglio cambiare font piuttosto che adattare il layout dell'editor.

Un aspetto decisamente meno importante è la resa del font con diverse formattazioni. Qui il fatto è che il codice è sempre "puro testo" non formattato: tuttavia molti editor applicano una formattazione automatica a seconda del contesto (per esempio, i commenti sono resi in corsivo, etc.). Ovviamente è possibile personalizzare (ed eventualmente abolire) queste scelte di formattazione, ma conviene comunque scegliere un font che sia leggibile anche in corsivo e in neretto.

Windows è già dotato di uno dei migliori font "da programmatore" in circolazione, ovvero Consolas che è uno dei font selezionabili nella shell cmd.exe. Molti preferiscono comunque la sua variante open source Inconsolata. Altre scelte molto popolari sono Anonymous Pro, Source Code Pro, Ubuntu Mono per chi è abituato a Linux (o qualche clone open source di Menlo o Monaco per chi è abituato al Mac). Ma le scelte sono veramente molte, e nuovi font interessanti nascono ogni giorno. Per iniziare, Consolas/Inconsolata andrà benissimo.

Librerie Python che potrebbero essere utili in Windows.

Per finire, una rapida rassegna di alcune librerie "Windows-oriented" che occasionalmente potrebbero tornare utili. Attenzione però: se usate alcuni di questi pacchetti rinunciate alla compatibilità cross-platform, e vi rivolgete esclusivamente all'ambiente Windows.

  • PyWin32 di Mark Hammond, è un wrapper intorno a molte api di Windows, in modo particolare le Win32 Api e COM. È un progetto vecchio e poco aggiornato, ma d'altra parte anche le api della controparte Windows sono molto stabili. La documentazione è scarsa, e si trova soprattutto all'interno del pacchetto sotto forma di un vecchio .chm: tuttavia, la vera documentazione a cui fare riferimento è quella delle api di Windows. Sul sito si possono scaricare delle versioni compilate (build) per varie versioni di Python, ma tutte pacchettizzate come eseguibili .exe. Da qualche tempo sono anche disponibili su PyPI e quindi installabili con Pip.
  • Pythonnet integra le CLR di .NET in Python, e viceversa. In pratica vuol dire che potete chiamare le API della CLR da dentro il vostro codice Python, oppure usare librerie Python da dentro il vostro codice C#. Si tratta naturalmente di uno strumento indispensabile se volete usare Python in .NET (l'alternativa è usare IronPython, vedi sotto). Siccome da qualche tempo la CLR di .NET è disponibile anche per Linux, si può ottenere un inaspettato livello di cross-compatibilità.
  • PyHook cattura eventi globali del mouse e della tastiera in Windows. È un progetto vecchio ma tutto sommato stabile e ben documentato (vedere la sezione "wiki"). L'installer ufficiale è un eseguibile, ma probabilmente è meglio usare le wheel di Chris Gohlke (anche per Python 3).
  • Py2exe permette di pacchettizzare script Python in eseguibili .exe per l'esecuzione su computer dove non è installato Python. Si tratta di un progetto molto vecchio, che non è mai stato convertito per Python 3: è preferibile usare Cx_freeze o PyInstaller, invece (vedi sotto). Se volete provare Py2exe, è meglio usare le wheel fornite da Chris Gohlke (dove si trova anche una versione non ufficiale per Python 3.4, che probabilmente quindi non funzionerà per le versioni 3.5/6/7 che richiedono un compilatore diverso). In generale, l'idea di distribuire software Python per Windows sotto forma di eseguibili .exe è chiaramente attraente, ed è anche una delle prime cose che un principiante desidera fare. Si tratta però di un argomento molto vasto e complesso: i tool come Py2exe funzionano bene nei casi semplici (progetti "pure-Python" senza dipendenze esterne complicate) ma non è affatto raro imbattersi in difficoltà di vario tipo.
  • Cx_freeze genera eseguibili .exe da script Python: a differenza di Py2exe, è attivamente sviluppato, ben documentato, installabile con Pip. Vi conviene comunque tenere d'occhio il bug tracker per avere un'idea dei possibili problemi che potreste avere.
  • PyInstaller è un'altra opzione da tentare per generare eseguibili .exe da script Python. Sviluppato, documentato, installabile con Pip, disponibile per Python 3. Anche in questo caso, se qualcosa va storto un'occhiata al bug tracker può essere d'aiuto.
  • Pynsist è ancora un'altra opzione per creare installer: è un wrapper intorno a NSIS che quindi va installato a parte e "globalmente" (poi Pynsist può essere installato con Pip anche in un venv).
  • WxPython è uno dei gui framework storici per Python. Anche se molti preferiscono i framework concorrenti basati sulle Qt (PySide e wxQt), wxPython ha un notevole seguito specialmente su Windows perché permette di realizzare interfacce grafiche con un look nativo sulle diverse piattaforme. Ne esistono due versioni: wxPython "classic" (la serie 3.x) è ormai superata; wxPython "Phoenix" è la nuova versione per Python 3 (ma compatibile anche per Python 2.7), che dopo lunga attesa è uscita dalla versione beta ed è ormai distribuita come wxPython 4.x. Phoenix si può installare normalmente con Pip. La demo, che è fondamentale per orientarsi, si deve scaricare separatamente e scompattare: una volta estratti i file in una directory qualunque, per avviare la demo basta un normale py demo.py dalla shell (ovviamente, dovete aver attivato il venv in cui avete già installato wxPython).

Distribuzioni alternative di Python.

Esistono alcune distribuzioni alternative di Python, curate da terze parti, che installano non solo Python e la sua libreria standard, ma anche una selezione curata di pacchetti e framework esterni. Fino a non molto tempo fa, come abbiamo visto, in Windows era difficile installare molti pacchetti con estensioni non pre-compilate: le distribuzioni alternative erano un modo facile per poter usare questi pacchetti, dal momento che i curatori della distribuzione li fornivano già pre-compilati. Con l'introduzione di Pip e del nuovo formato Wheel, è diventato molto più facile trovare pacchetti pre-compilati per Windows, e ormai non c'è quasi più bisogno di ricorrere a distribuzioni alternative solo come escamotage per usare certi pacchetti. Ha senso invece ricorrere a una distribuzione alternativa se offre un reale vantaggio rispetto al tipo di lavoro che vogliamo fare (per esempio, Anaconda per certi ambiti scientifici, tecnologici, accademici).

  • WinPython ha il vantaggio di essere completamente "portable": non richiede installazioni, ed è interamente compresa in una directory. E' orientata alla comunità scientifica; offre l'ambiente grafico PyQt, e l'IDE Spyder.
  • PythonXY è analoga a WinPython (Qt e Spyder compresi), ma è disponibile solo per Python 2.
  • ActivePython è una delle distribuzioni storiche di Python. Più orientata all'ambiente corporate, il suo vero punto di forza è probabilmente la stabilità dei pacchetti selezionati e il customer support.
  • Anaconda è forse la distribuzione più famosa, popolarissima in ambito scientifico. È una vera e propria piattaforma multi-linguaggio (oltre a Python, anche R) basata sul packet manager Conda. Installa automaticamente oltre 150 pacchetti, e altre centinaia sono installabili successivamente con Conda.
  • Canopy è il competitor di Anaconda, molto simile come target (comunità scientifica) e strumenti (packet manager proprietario, editor grafico, centinaia di pacchetti supportati...). Le differenze sono apprezzabili praticamente solo nei termini dei diversi ambiti applicativi: alcune comunità lavorano su Canopy, altre su Anaconda.

Implementazioni alternative di Python.

L'implementazione ufficiale di Python, l'unica sviluppata e supportata dalla Python Software Foundation, è CPython, scritta in C, che è quella che abbiamo preso fin qui in considerazione. Ma esistono altre implementazioni curate da terze parti: le più note sono Jython il cui bytecode viene eseguito dalla Java Virtual Machine, e PyPy, un'implementazione di Python scritta in CPython che offre un JIT compiler e stackless mode per aumentarne velocità e capacità in concurrency.

Un'implementazione dedicata al mondo Windows è IronPython, scritta in C# e integrata in .Net: uno script IronPython può usare le librerie .Net allo stesso modo delle consuete librerie Python. Purtroppo IronPython implementa solo Python 2, ma di recente lo sviluppo è ripreso e ci sono piani per implementare anche Python 3.

Parte ottava: Python, Windows e Unicode.

Dedichiamo questa sezione all'esame di alcuni problemi legati all'uso di Unicode in Windows. Ricordiamo che questa non è una guida introduttiva a Unicode. Le note che seguono presuppongono una certa conoscenza operativa su Unicode, gli encoding Unicode e gli encoding regionali, gli strumenti Unicode di Python e il loro uso.

Unicode nella shell.

Se usate Python per costruire programmi a interfaccia grafica (GUI), in genere non dovete preoccuparvi troppo di Unicode. I moderni GUI framework supportano Unicode in maniera trasparente, e in pratica per usarli basta sapere come funziona una stringa in Python. Se invece la parte I/O del vostro programma si appoggia alla shell (come avviene sempre, tra l'altro, nei programmi dei principianti), allora è molto facile che finirete per inciampare in qualche problema legato a Unicode. In genere il principiante non si preoccupa se ogni tanto nei suoi esercizi qualche carattere "strano" viene fuori "sbagliato". Tuttavia esistono anche programmi professionali a interfaccia testuale (CLI), e se intendete percorrere questa strada dovete considerare attentamente Unicode.

Per cominciare, tenente presente che il problema spesso non riguarda Python. Se il font usato dalla shell non ha un certo glifo, non può visualizzare quel carattere. I font disponibili in cmd.exe sono in genere Lucida Console e Consolas, ed entrambi coprono relativamente poco dello spazio Unicode. Potete cambiare font facendo clic col pulsante destro nella barra del titolo della shell e selezionando "Proprietà". Fate la prova con questi caratteri cirillici esotici, che Consolas copre ma Lucida Console no: "ѧ Ѩ Ѫ ѭ Ѯ". Copiateli da questa pagina del vostro browser e provate a incollarli nella shell (clic col destro, e "incolla"). A seconda del font impostato, vedrete correttamente i glifi oppure solo dei "segnaposto". Potete controllare esattamente quali caratteri sono supportati da un font usando tool come BabelMap. Aggiungere un font a quelli disponibili in cmd.exe è possibile, ma solo aggiungendo una chiave alla sezione HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont del registro di configurazione: in definitiva non conviene. Il problema di fondo è che cmd.exe non è una shell Unicode: se avete bisogno di visualizzare caratteri arbitrari, usate ConEmu (di cui abbiamo già parlato), o PowerShell ISE (già disponibile in Windows). Queste shell sono in grado di visualizzare contemporaneamente diversi font, e ricorrono di volta in volta a quelli in grado di farvi vedere i caratteri necessari (all'incirca come fa il vostro browser). Resta inteso che, se nessun font tra quelli installati sulla vostra macchina copre un certo carattere, allora in quel punto resterà sempre un "segnaposto".

In secondo luogo, ricordate che la shell non usa di solito lo stesso encoding di default che usa Windows (detto "encoding Ansi"). Almeno da noi in Italia, "Ansi" è cp1252 (che, vale la pena di ricordarlo, non coincide con "Latin 1" come spesso si crede) mentre cmd.exe usa l'encoding "OEM" che per noi in Italia è cp850. Anche se Python in pratica può ignorare la cosa (ma solo a partire dalla versione 3.6 compresa!), quando usate strumenti della shell come type dovete ricordarvi della discrepanza. Per esempio, aprite un file con il Blocco Note, scriveteci dei caratteri accentati qualsiasi, e salvate. Se adesso dalla shell provate a vedere il contenuto del file con type test.txt, vedrete caratteri sbagliati perché Blocco Note di default salva in cp1252. All'inverso, se inviate il contenuto della shell a un file di testo, per esempio con copy con test.txt, quando aprite il file con il Blocco Note vedrete di nuovo caratteri sbagliati perché la shell lavora in cp850 e Blocco Note apre il file in cp1252. Potete in ogni caso cambiare l'encoding della shell, impostando per esempio quello di default di Windows, con il comando chcp 1252: dopo di che, queste operazioni funzioneranno senza problemi (ricordiamo che chcp senza argomenti vi mostra l'encoding attualmente attivo).

Per fortuna in Python, almeno a partire dalla versione 3.6, questo non è un problema. Operazioni come print e input riescono senza problemi, grazie al fatto che la Pep 528 impone ormai a Python di comunicare con la shell usando le versioni Unicode delle API di Windows. Questo vuol dire che voi potete ignorare i dettagli dell'encoding della shell, Windows fa tutto il lavoro sporco dietro le quinte e voi dal lato Python vi ritrovate sempre con le stringhe Unicode "giuste". Provate a eseguire questo semplice script:

# test.py
print('test Latin 1: à á â ã ä å æ ç è é ê')
print('test Greek: ά έ ή ί ΰ α β γ δ ε ζ η θ')
print('test Cyrillic: й к л м н о п р с т у ф\n')
s = input('scrivi qualcosa: ')
print('\nquello che hai scritto:', s)

Potete provare questo script sia con cp850 sia con cp1252 nella shell, ma il risultato è sempre buono (almeno finché non cercate di stampare un carattere non supportato dal font in uso!), e non dovete preoccuparvi di fare manualmente operazioni di decode e di encode nel codice Python.

La situazione precedente a Python 3.6 (compreso quindi Python 2.7) è... non buona. Prima della Pep 528 Python usava le vecchie API Ansi di Windows, deprecate da tempo, e questo comportava parecchi problemi. Se vi serve un'analisi approfondita della situazione precedente, potete consultare la Issue 1602 nel bug tracker di Python, o leggervi il Readme della Windows Unicode Console che implementa molti dei fix che poi sono stati inseriti nella Pep 528. Anche se non avete Python 3.5 installato, potete ripristinare il vecchio comportamento settando la variabile d'ambiente PYTHONLEGACYWINDOWSSTDIO (a qualsiasi valore diverso da zero). Se provate a eseguire il nostro script con questo "legacy mode" attivo e l'encoding di default cp850 nella shell, vedrete che prima di tutto la stampa delle righe di test non va a buon fine perchè Python prova a encodarle in cp1252. Anche l'eco dei caratteri inseriti può essere sbagliato: provate per esempio con il simbolo dell'euro... D'altra parte, se impostate l'encoding della shell a cp1252 prima di eseguire lo script, le cose torneranno a funzionare. In alternativa, potete forzare l'encoding giusto direttamente nel codice Python.

Se siete in dubbio, sys.stdout.encoding vi restituisce l'encoding della shell: in Python 3.6+ dovrebbe essere UTF8, altrimenti cp850 o qualsiasi code page abbiate attivato nella shell prima di avviare Python.

Unicode nei nomi dei file.

In Windows il file system è "Unicode" (più precisamente, le path sono in utf16-le), ma Python ha sempre usato le API Ansi di Windows per colloquiare con il file system, con effetti collaterali sgradevoli. La situazione è analoga a quella appena vista per la shell, ed è stata risolta in modo identico: la Pep 529, gemella della Pep 528 vista sopra, impone a Python 3.6+ di usare le API Unicode anche per le chiamate al file system.

Vi rimandiamo alla lettura di questa Pep per i dettagli, ma il succo è questo. Nella situazione precedente, non c'erano comunque problemi almeno finché le path venivano rappresentate come stringhe (in Python 3) ovvero stringhe Unicode (in Python 2). Quando però le path erano rappresentate come bytes (Python 3) ovvero come stringhe "semplici" (Python 2), allora le API Ansi sottostanti usavano naturamente l'encoding Ansi regionale per convertire avanti e indietro da utf16-le. E quando un carattere non è coperto dall'encoding Ansi, finisce sostituito da un segnaposto. Di conseguenza non è garantito che sia possibile "fare il giro completo", ovvero leggere il nome di un file, conservarlo in una variabile, e usare quella variabile per aprire il file.

Per capire il problema, create un file con qualche carattere cirillico nel nome (ricordate: usiamo i caratteri cirillici perché non sono coperti da cp1252 ma sono comunque visualizzabili dal font Consolas, che vi conviene usare nella shell cmd.exe. Se però usate una shell Unicode come ConEmu o PowerShell ISE, o se semplicemente non vi interessa visualizzare l'output del vostro script nella shell, allora potete sbizzarrirvi con qualsiasi carattere esotico). Diciamo che il file si chiama йклмн.txt. Fate prima una prova con Python 2 (ovvero, situazione pre-Pep 529):

> py -2
[...]
>>> import os
>>> d = os.listdir(u'.') # nota bene! se passo unicode... 
>>> d                    # ... ottengo unicode
[u'\u0439\u043a\u043b\u043c\u043d.txt']
>>> open(d[0]).close()   # a questo punto aprire il file va a buon fine

>>> d = os.listdir('.')  # se invece passo bytes (stringhe normali in py2)... 
>>> d                    # ... ottengo bytes 
['?????.txt']
>>> # ma adesso nella conversione ho perso il nome vero del file...

Il risultato di os.listdir, come di molte altre funzioni analoghe in Python, mantiene il tipo dell'argomento che passate: se passate una path in Unicode, ottenete una (lista di) path in Unicode; se passate bytes, avrete bytes. Il problema però è che dietro le quinte Python usa le API Ansi di Windows, e pertanto quando passate bytes l'encoding è quello locale cp1252, che non è in grado di coprire i caratteri della nostra path, che quindi ritorna mutilata.

La stessa situazione si verifica in Python 3, ricordando che le stringhe "normali" equivalgono alle stringhe Unicode di Python 2. Se avete solo Python 3.6+ installato, potete comunque ripristinare la vecchia situazione settando una variabile d'ambiente:

>set PYTHONLEGACYWINDOWSFSENCODING=1
>py -3
[...]
>>> import os
>>> os.listdir('.')  # usare stringhe (Unicode) funziona...
['йклмн.txt']
>>> os.listdir(b'.') # ... usare bytes (in cp1252) no
[b'?????.txt']

Invece, in Python 3.6+ senza "legacy mode" attivo, finalmente non ci sono problemi anche se usate le path sotto forma di bytes:

>>> os.listdir(b'.')
[b'\xd0\xb9\xd0\xba\xd0\xbb\xd0\xbc\xd0\xbd.txt']

Tutto questo è interessante, ma forse vi state chiedendo: perché uno vorrebbe esprimere le path sotto forma di bytes invece che come stringhe (Unicode)? E anzi, perché Python dovrebbe permettere che le path siano bytes? Non sarebbe più facile impedire di usare bytes per esprimere le path? La risposta a queste domande è: perché, piaccia o no, nel mondo Posix le path sono bytes. La Pep 529 chiarisce anche questi aspetti di compatibilità.

Abilitare i nomi lunghi dei file.

Ancora a proposito di path, ricordiamo qui che a partire dalla versione 3.6 Python supporta i "nomi lunghi" del file system NTFS in funzioni come open, o in quelle del modulo os etc. Questo è un effetto collaterale di usare le API Unicode di Windows (che appunto supportano i nomi lunghi). Attenzione però: questo vale solo se esprimete le path come stringhe (Unicode), e non funziona se le esprimete come bytes (vedi sopra per i dettagli).

La questione dei "nomi lunghi" non riguarda Python in senso stretto, ed è facile documentarsi in rete in proposito.

Unicode nei file.

Qui Python, come è ovvio, non ha alcun potere. In generale, quando il testo è "salvato" da qualche parte, si trova in forma di bytes e quindi con un determinato encoding. Quando "leggete" il testo recuperandolo dalla sua sorgente (e simmetricamente quando lo "salvate") dovete fare un'operazione di decoding da (o di encoding in) quell'encoding per convertire i bytes in/da oggetti Unicode che Python (3) usa internamente. Per esempio,

with open('test.txt', 'r', encoding='cp1252') as f: # "f" e' uno stream di bytes
    s = f.read() # "s" e' una stringa (ovvero un oggetto Unicode)

Come potete sapere qual è l'encoding di una sorgente di testo esterna? Beh, ecco il problema: nel caso più generale, non c'è modo di esserne sicuri. Certamente alcune sorgenti sono più "trattabili" di altre: un database ha un encoding dichiarato, e il driver Python che usate per connettervi in genere è in grado di capirlo; un file html ha un "meta-tag" di encoding, se è correttamente formato; e così via. Certo anche in questi casi nessuno può proteggervi da dati malformati e dichiarazioni di encoding non rispettate, ma tutto sommato non sono casi frequenti. Un semplice, generico file di testo, d'altra parte, non ha un modo ovvio di dichiarare l'encoding. Supporre che il file sia in UTF8 è una scommessa buona come un'altra: in realtà molto dipende da chi, e dove, ha generato il file di testo.

Un file di testo "puro" (.txt, per intenderci) generato in ambiente Windows di solito non è in UTF8, a meno che non sia stato creato da un utente più esperto per esempio con un editor da programmatore, o non sia l'output di un sofware che dichiara di produrre file UTF8. Ma per quanto riguarda l'utente comune, il tool di default per aprire e modificare questi file è il Blocco Note (notepad.exe) che, in condizioni normali, salva il file con l'encoding regionale variabile Ansi: come abbiamo detto, da noi in Europa occidentale, "Ansi" vuol dire cp1252. Blocco Note può salvare in UTF8, ma occorre specificarlo al momento del salvataggio: e di solito l'utente normale non se ne cura. Fa eccezione il caso in cui il testo contiene caratteri non coperti da cp1252: allora Blocco Note, al momento del salvataggio, avvisa l'utente e propone di salvare in un formato diverso. Le scelte possibili, abbastanza criptiche, sono "Unicode" (ovvero utf16-le), "Unicode Big Endian" (utf16-be), e finalmente "UTF8".

E questo introduce il problema aggiuntivo del BOM: il modo in cui Blocco Note riconosce l'encoding UTF8/16 è appunto controllando la presenza del BOM all'inizio del file: se non lo trova, assume una codifica Ansi. In particolare, quindi, Blocco Note usa anche il BOM UTF8 che come è noto non è obbligatorio e molte applicazioni preferiscono non usare. Si tratta dei tre bytes EF BB BF che corrispondono ai caratteri stampabili  in cp1252. Naturalmente Blocco Note non visualizza l'eventuale BOM iniziale, e lo stesso fanno altre applicazioni (per esempio i browser) che riconoscono il BOM. Per vedere con sicurezza se il BOM è presente o meno, potete aprire il file con un editor esadecimale.

Python non attribuisce un particolare significato al BOM UTF8: seguendo le indicazioni dello standard Unicode, lo tratta come un singolo carattere invisibile (ricordiamo che in UTF8 un "carattere" può essere lungo da 1 a 4 bytes). Fate un prova: aprite un file nuovo con il Blocco Note e scriveteci dentro solo un breve testo con caratteri accentati, per esempio cìàò (4 lettere). Scegliete "Salva con nome" e salvate in formato "UTF8". Aprite adesso questo file con Python:

>>> with open('test.txt', 'r', encoding='utf8') as f:
...    s = f.read()
>>> s # ecco il BOM 
'\ufeffcìàò'
>>> len(s) # il BOM e' lungo un carattere
5
>>> print(s) # "print" stampa il BOM come carattere invisibile
cìàò
>>> s[:3] # il BOM conta come un carattere anche per lo slicing!
'\ufeffcì'

Naturalmente, se invece aprite il file con l'encoding sbagliato cp1252, il BOM viene interpretato come tre caratteri distinti immediatamente riconoscibili:

>>> with open('test.txt', 'r', encoding='cp1252') as f:
...    s = f.read()
>>> s # il BOM sono i primi 3 caratteri: 
¬Ã Ã²

In linea di principio, il problema è che al momento di aprire un file non potete essere sicuri dell'encoding, della presenza di BOM: un file potrebbe essere UTF8 ma generato da un editor, diverso da Blocco Note, che non mette il BOM. Certo, se esiste il BOM allora è quasi certamente UTF8 (e lo stesso vale per i BOM di UTF16): ma per aprire un file occorre specificare un encoding prima di sapere se dentro c'è il BOM; e se sbagliate encoding potreste ritrovarvi con caratteri incomprensibili o con un errore di decoding. Viceversa, se il BOM non è presente, allora l'encoding potrebbe essere letteramente uno qualsiasi: UTF8 senza BOM, oppure un encoding Ansi regionale di Windows, o altro ancora.

Come abbiamo detto, il problema è senza soluzione, almeno nel caso più generale. In pratica però è spesso possibile fare delle assunzioni ragionevoli se avete qualche idea di come è stato prodotto il file. Se sapete che il file viene da un signore polacco che usa Windows e non è un esperto di Unicode, allora probabilmente l'encoding sarà cp1250 (il default Ansi in Polonia). Se però non avete informazioni, non vi resta che andare per tentativi: ma allora vi conviene piuttosto adottare un pacchetto di "encoding detection" già pronto, come per esempio Chardet.

Infine, che cosa succede con i file prodotti da Python e aperti successivamente con il Blocco Note? Se scrivete il file con l'encoding Ansi cp1252, allora il file sarà normalmente leggibile da Blocco Note. Naturalmente, se nel vostro testo ci sono caratteri non coperti da cp1252, sarà Python per primo a dirvi che non è possibile scrivere il file:

>>> with open('test.txt', 'a', encoding='cp1252') as f:
...     f.write('cìàò')
...
4
>>> with open('test.txt', 'a', encoding='cp1252') as f:
...     f.write('й к л м н о п р с т у ф')
...
Traceback (most recent call last):
[...]
UnicodeEncodeError: [...]

Se invece scrivete il file in UTF8, le cose si complicano perché Python non inserisce il BOM iniziale:

>>> with open('test.txt', 'a', encoding='utf8') as f:
...     f.write('cìàò')
...
4
>>> # notare che sono stati scritti 4 caratteri: niente BOM!

Potete verificare che il BOM non è presente aprendo per prima cosa il file con un editor esadecimale. Tuttavia, quando aprite il file con Blocco Note, sorpresa: il file si legge benissimo. In effetti Blocco Note ha l'euristica necessaria per accorgersi dell'encoding anche senza trovare il BOM, e visualizza il contenuto senza problemi. Adesso, se chiudete il file senza salvare, Blocco Note non ne modifica il contenuto. Ma se invece salvate, anche senza aver apportato nessuna modifica visibile, allora Blocco Note ne approfitta per rimettere le cose a posto e aggiungere il BOM (potete controllare di nuovo con un editor esadecimale).

Link di riferimento.

Riassumiamo qui alcuni link utili: il sito ufficiale di CPython, i download per Python 3.6 e Python 2.7. La documentazione ufficiale e la sua sezione dedicata a Windows. La PEP 8 e la PEP 257, il manuale di stile Python.

Per quanto riguarda pacchetti e distribuzione: PyPI, la guida a come distribuire i pacchetti Python e la guida ufficiale alla distribuzione. La documentazione di Pip. L'alternativa avanzata Pipenv. Le wheel non ufficiali di Chris Gohlke.

Librerie di uso comune: Sphinx per la documentazione. Pep8, PyLint o Flake8 per il linting. Unittest, PyTest, Nose, Fixtures e Tox per i test.

Librerie Windows-orientend: PyWin32, Pythonnet, PyHook, WxPython, Cx_freeze, PyInstaller, Pynsist, Py2exe.

Tools: il terminale ConEmu/Cmder. Git per Windows. La shell interattiva Jupyter Notebook. Gli editor testuali: Vim, Emacs. Gli IDE: Eclipse/PyDev, PyCharm, Visual Studio Community/Python Tools per Visual Studio, WingIde, Spyder. Gli editor grafici: Sublime Text, Notepad++, Atom, Brackets, Visual Studio Code.

Distribuzioni alternative: Anaconda, Canopy, ActivePython, WinPython, PythonXY.

Implementazioni alternative: PyPy, Jython, IronPython.

A proposito della shell: una guida a cmd.exe e la guida di Bash (ma forse potete cominciare da questa cheat list). Come aprire una shell "privilegiata". Una guida alle variabili d'ambiente in Windows, e alla path di sistema in particolare.

A proposito di Unicode: una vecchia ma ancora fondamentale guida e l'how-to della documentazione Python.

@maxpigreco
Copy link

maxpigreco commented Apr 10, 2020 via email

@ricpol
Copy link
Author

ricpol commented May 11, 2020

Il mio libro Python in Windows è uscito!
Parla di queste cose in modo molto più aggiornato e completo... vi suggerisco di dargli un'occhiata...

@callpri
Copy link

callpri commented Oct 28, 2024

Il mio editor Python consigliato è Codelobster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment