1 14/04/2026 9 min

Su Ubuntu la parola “dipendenze Python” può voler dire tre cose diverse: pacchetti di sistema, librerie per un singolo progetto e moduli che servono a un servizio in produzione. Se non distingui questi casi, finisci quasi sempre per mescolare apt, pip e ambiente globale, con effetti collaterali inutili. La regola pratica è semplice: usa il gestore pacchetti del sistema per ciò che deve restare integrato con Ubuntu, usa un ambiente virtuale per il progetto, e tocca il Python di sistema solo quando sai esattamente perché.

La scelta giusta prima di installare

Se devi far girare uno script, un’app Flask, un tool interno o una pipeline, la strada più pulita è quasi sempre questa: installi il runtime Python richiesto, crei un ambiente virtuale, poi installi lì dentro le dipendenze del progetto. Così eviti conflitti tra versioni di librerie, aggiornamenti indesiderati e rotture quando Ubuntu aggiorna i pacchetti di base.

Se invece ti serve una libreria usata da più componenti del sistema, o un modulo che Ubuntu prevede come dipendenza di altri pacchetti, allora ha senso passare da apt. In quel caso stai gestendo pacchetti Debian, non un ambiente applicativo isolato.

Verifica il punto di partenza

Prima di installare qualsiasi cosa, controlla quali versioni hai già sul sistema. Non è un dettaglio: su Ubuntu possono coesistere più interpreter, e non sempre quello lanciato da shell è quello che pensi.

Comandi utili:

python3 --version
which python3
python3 -m pip --version
lsb_release -a

Se python3 -m pip --version restituisce un errore, significa che pip non è installato per quell’interprete oppure l’ambiente è incompleto. Se which python3 punta a un percorso inatteso, stai probabilmente usando un binario diverso da quello del sistema o del virtualenv.

Pacchetti di sistema: quando usare apt

Per installare il supporto base di Python su Ubuntu, il punto di partenza è apt. Di solito servono almeno l’interprete, venv e i file di sviluppo se devi compilare moduli nativi.

sudo apt update
sudo apt install python3 python3-venv python3-pip python3-dev

Questo installa i componenti principali:

  • python3: interprete di base.
  • python3-venv: supporto per ambienti virtuali.
  • python3-pip: gestore pacchetti Python associato al sistema.
  • python3-dev: header e librerie per compilare estensioni C/C++.

Se il tuo progetto include moduli come psycopg2, lxml, Pillow o altre dipendenze con estensioni native, spesso servono anche librerie di sviluppo aggiuntive installate via apt. Per esempio, per lavorare con PostgreSQL o immagini, potresti aver bisogno di pacchetti come libpq-dev o libjpeg-dev. La regola è: il pacchetto Python si installa con pip, ma i prerequisiti di compilazione si installano con apt.

Ambiente virtuale: il metodo corretto per i progetti

Su Ubuntu moderno, l’approccio standard per i progetti è un virtualenv. Ti isola le dipendenze, evita di sporcare il sistema e rende riproducibile il deployment. Se devi spiegare una sola abitudine “buona”, è questa.

mkdir -p ~/progetti/mioapp
cd ~/progetti/mioapp
python3 -m venv .venv
source .venv/bin/activate

Dopo l’attivazione, il prompt cambia e i comandi python e pip puntano al virtualenv. Verifica sempre:

which python
which pip
python --version
pip --version

Il risultato atteso è che i percorsi puntino a qualcosa come ~/progetti/mioapp/.venv/bin/python. Se invece vedi ancora /usr/bin/python3, l’ambiente non è stato attivato o stai usando un terminale con configurazione anomala.

Installare le dipendenze con pip nel modo giusto

Una volta dentro il virtualenv, installa i pacchetti dal file del progetto o direttamente dai nomi necessari. Il caso più comune è un requirements.txt.

python -m pip install --upgrade pip
python -m pip install -r requirements.txt

Usare python -m pip invece di pip nudo riduce gli errori di contesto. Così sei certo che pip stia operando sull’interprete corretto. In ambienti misti, questa differenza evita metà dei ticket “ho installato il pacchetto ma non viene trovato”.

Se non hai ancora un file delle dipendenze, puoi generarlo in modo controllato dopo aver verificato che l’app funzioni:

python -m pip freeze > requirements.txt

Non usare questo file come lista universale per qualsiasi macchina senza pensarci: freeze fotografa anche dipendenze transitive e versioni esatte, utile per replica e deploy, meno utile per un template pulito di progetto.

Dipendenze di sistema per moduli Python con estensioni native

Molti errori di installazione non dipendono da Python, ma dal fatto che il pacchetto tenta di compilare codice nativo e trova mancanti header o toolchain. In quel caso il sintomo tipico è un errore durante pip install con riferimenti a gcc, Python.h, pg_config o librerie mancanti.

La correzione è quasi sempre una combinazione di pacchetti di sviluppo e tool base:

sudo apt install build-essential python3-dev

Se il pacchetto fallisce ancora, devi leggere il log completo e cercare il primo errore reale, non l’ultimo. Un esempio classico: fatal error: Python.h: No such file or directory indica quasi sempre python3-dev mancante. Se trovi pg_config not found, il problema è lato PostgreSQL e serve il pacchetto di sviluppo associato.

Esempio pratico: installare Flask in modo pulito

Prendiamo un caso semplice ma realistico: vuoi creare una piccola app Flask su Ubuntu. La procedura corretta non parte con sudo pip install flask, ma con un progetto isolato.

sudo apt update
sudo apt install python3 python3-venv python3-pip
mkdir -p ~/progetti/flask-demo
cd ~/progetti/flask-demo
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install flask

A questo punto puoi creare un file app.py minimale:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "OK"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Avvio di test:

python app.py

Verifica con un secondo terminale:

curl -i http://127.0.0.1:5000/

Se ricevi HTTP/1.1 200 OK e la stringa OK, la catena base è corretta. Se non funziona, il problema non è “Flask non installato” ma più probabilmente ambiente non attivato, porta occupata o errore nel file applicativo.

Quando serve installare un pacchetto solo per il sistema

Ci sono casi in cui non vuoi un virtualenv. Ad esempio, un tool di amministrazione usato da root, uno script di provisioning o un componente che deve essere presente per tutti gli utenti. In questi scenari puoi usare apt per i moduli disponibili nei repository Ubuntu.

Per cercare i pacchetti disponibili, puoi usare:

apt-cache search python3 | less
apt show python3-requests

Se trovi il pacchetto desiderato nei repository, installarlo via apt è preferibile rispetto a forzare pip nel sistema. Il vantaggio è che ricevi aggiornamenti coerenti con il resto della distribuzione e riduci il rischio di conflitti con dipendenze di altre applicazioni.

Evita il classico errore del pip globale

Su Ubuntu recente, installare pacchetti Python globali con sudo pip è una cattiva abitudine. Non è solo una questione di “pulizia”: può rompere strumenti di sistema, sovrascrivere file gestiti da apt e creare un ambiente non più aggiornabile in modo sicuro.

Se ti serve davvero un’installazione globale fuori dal package manager, valuta invece una delle alternative sane: virtualenv dedicato, pipx per tool standalone, pacchetto Debian creato ad hoc, oppure container. pipx è utile per utility come black, poetry, httpie e strumenti simili che vuoi tenere isolati ma accessibili da shell.

sudo apt install pipx
pipx ensurepath
pipx install httpie

Con pipx ogni tool vive nel proprio ambiente, senza sporcare il Python di sistema. È una soluzione più pulita del globale e più semplice da gestire di un virtualenv manuale per ogni comando singolo.

Gestire dipendenze con file riproducibili

In produzione o su workstation condivise, non basta dire “installa quei pacchetti”. Serve un elenco riproducibile. Il formato più comune è requirements.txt, ma in progetti più strutturati puoi usare anche pyproject.toml con lock file dedicato, a seconda del tool scelto.

Una pratica utile è separare ciò che serve in esecuzione da ciò che serve in sviluppo. Per esempio:

requirements.txt
requirements-dev.txt

Nel primo metti solo le dipendenze runtime; nel secondo aggiungi formatter, test runner, linter e strumenti di debug. Così l’ambiente di produzione resta più piccolo e più facile da auditare.

Controlli finali dopo l’installazione

Dopo aver installato le dipendenze, non fermarti al “comando è andato a buon fine”. Verifica che il progetto importi davvero i moduli e che l’interprete sia quello previsto.

python -c "import sys; print(sys.executable)"
python -c "import flask; print(flask.__version__)"

Se l’import fallisce, hai un problema di ambiente, non di installazione generica. Se la versione stampata non coincide con quella attesa, stai usando un interprete diverso da quello del virtualenv o del sistema che pensavi di aver configurato.

Se il tuo servizio gira con systemd, verifica anche che il servizio punti all’interprete corretto. Un file unit tipico dovrebbe usare il binario nel virtualenv, non /usr/bin/python3 a caso. Un estratto utile è questo:

[Service]
WorkingDirectory=/opt/mioapp
ExecStart=/opt/mioapp/.venv/bin/python /opt/mioapp/app.py

Qui il punto non è solo “far partire il servizio”, ma garantirti che in riavvio e deploy venga usato sempre lo stesso set di dipendenze.

Errori comuni e lettura rapida del sintomo

  • ModuleNotFoundError: il modulo non è installato nell’ambiente giusto o il virtualenv non è attivo.
  • externally-managed-environment: stai tentando un pip install globale su un Python gestito da Ubuntu; usa un virtualenv o apt.
  • Python.h not found: manca python3-dev.
  • pg_config not found: mancano le librerie di sviluppo PostgreSQL.
  • Permission denied: stai installando in una directory senza permessi o stai usando sudo dove non serve.

Buone pratiche da tenere ferme

La parte più importante non è il comando singolo, ma la disciplina operativa. Se lavori su Ubuntu e vuoi evitare problemi futuri, tieni ferme queste regole: sistema con apt, progetto con venv, tool standalone con pipx, compilazione nativa solo con i prerequisiti di sviluppo già presenti.

In più, documenta sempre la dipendenza tra codice e ambiente. Se un’app richiede Python 3.11, scrivilo nel progetto e verifica la versione con un controllo esplicito. Se il servizio dipende da librerie native, annota anche i pacchetti apt necessari. Questa traccia vale più di una procedura “a memoria”.

Se vuoi una sintesi operativa: per installare dipendenze Python su Ubuntu, non chiederti solo “come faccio ad aggiungerle”, ma “dove devono vivere” e “chi le gestisce”. Se rispondi bene a queste due domande, i problemi scendono drasticamente.