Basi

Moduli e pacchetti Python: import, pip, venv e librerie in parole semplici

Aggiornato: · Skillaria.Top

Un modulo in Python è un file .py, un pacchetto è una cartella di moduli, una libreria è un insieme di pacchetti che si importano con la parola import. Le librerie esterne si installano con pip (o uv) in un ambiente virtuale venv, cioè una cartella isolata con interprete e pacchetti di un solo progetto, così le versioni di progetti diversi non entrano in conflitto.

Un modulo in Python è un normale file con del codice, e import è il modo per prendere da esso funzioni e classi. I moduli si raggruppano in pacchetti, i pacchetti formano le librerie, e per evitare che le librerie di progetti diversi si intralcino si installano in un ambiente virtuale venv. Vediamo l'intera catena: che cosa succede durante un import, come è fatto un pacchetto, come funzionano pip e venv in Python e quali sono i lazy import introdotti nella Python 3.15.

Modulo, pacchetto, libreria: qual è la differenza

ConcettoChe cos'èEsempio
ModuloUn singolo file .py; il nome del modulo è il nome del file senza estensionecategorie.py → import categorie
PacchettoCartella con moduli e il file __init__.pyspese/report.py → from spese.report import build
LibreriaUn insieme pronto di moduli e pacchetti per un certo compitorequests, pandas, la standard pathlib
Distribuzione (pacchetto PyPI)Archivio installato da pippip install requests

Nel parlato «libreria», «pacchetto» e «modulo» vengono spesso confusi, ed è normale. L'importante è sapere che tecnicamente import carica sempre un modulo o un pacchetto, mentre pip installa una distribuzione da PyPI, all'interno della quale ci sono i pacchetti.

Come funziona import in Python

Esistono diverse forme di import, e tutte compaiono nel codice reale:

import math                    # intero modulo, uso come math.sqrt
from math import sqrt, pi      # singoli nomi
import datetime as dt          # alias
from collections import Counter as C

print(math.sqrt(16), sqrt(9), pi)
print(dt.date.today())

Gli alias sono consolidati per le librerie grandi: import numpy as np, import pandas as pd. La forma from modulo import * è meglio evitarla: riempie lo spazio dei nomi e nasconde la provenienza dei nomi.

Che cosa fa davvero import

  1. Cerca il modulo nella cache sys.modules. Se è già caricato, lo restituisce e basta.
  2. Se non c'è, cerca il file nelle cartelle elencate in sys.path: la cartella dello script avviato, la libreria standard, il site-packages dell'ambiente.
  3. Esegue il file trovato per intero, dall'alto verso il basso.
  4. Mette l'oggetto modulo nella cache e lo associa al nome.

Da questo derivano due conseguenze pratiche. Un secondo import dello stesso modulo costa quasi nulla: il codice non viene eseguito di nuovo. In compenso, tutto il codice al livello più alto del modulo, compresi print e i calcoli pesanti, viene eseguito già durante l'import.

import sys
for p in sys.path:
    print(p)
print("math" in sys.modules)

if __name__ == "__main__"

Poiché l'import esegue il file, serve un modo per distinguere «sono stato avviato come script» da «sono stato importato». Lo fa la variabile __name__: quando il file viene eseguito è uguale a "__main__", quando viene importato è uguale al nome del modulo.

# categorie.py
def guess(title: str) -> str:
    return "cibo" if "bar" in title.lower() else "altro"

if __name__ == "__main__":
    print(guess("Bar vicino a casa"))   # viene eseguito solo con python categorie.py

Per un pacchetto esiste un'alternativa: un file __main__.py al suo interno e l'avvio con python -m spese.

Moduli standard di Python

Python arriva «con le batterie incluse»: centinaia di moduli integrati sono disponibili subito, senza installazione. I più usati:

ModuloA che cosa serve
os, sys, pathlib, shutilSistema, percorsi, file
json, csv, pickleFormati di dati
datetime, time, calendarData e ora
math, random, statistics, fractionsNumeri
re, stringLavoro con il testo
collections, itertools, functoolsStrutture dati e iteratori
logging, argparse, subprocessLog, argomenti da riga di comando, avvio di programmi
asyncio, threadingAsincronia e thread

L'elenco completo dei moduli della libreria standard è in sys.stdlib_module_names (Python 3.10+). Per vedere che cosa contiene un modulo si usano dir(math) e help(math).

Un pacchetto proprio: struttura del progetto

Quando i moduli diventano molti, si raccolgono in un pacchetto. Una struttura molto diffusa è lo src-layout:

spese-progetto/
├── pyproject.toml
└── src/
    └── spese/
        ├── __init__.py
        ├── cli.py
        ├── parsing.py
        ├── categorie.py
        └── report.py

All'interno del pacchetto i moduli si importano a vicenda con il nome del pacchetto (from spese.categorie import guess) oppure in modo relativo (from .categorie import guess). L'import relativo funziona solo dentro il pacchetto, non in un file avviato direttamente come script.

pip in Python: installazione delle librerie

Le librerie di terze parti si trovano nel catalogo PyPI e si installano con pip, che è incluso in Python. Conviene richiamarlo tramite l'interprete: così la libreria finisce proprio nel Python con cui eseguite il codice.

python -m pip install requests          # installare
python -m pip install "pandas>=2.3"     # con limite di versione
python -m pip install --upgrade requests
python -m pip uninstall requests        # rimuovere
python -m pip list                      # elenco dei pacchetti installati
python -m pip show requests             # versione e dipendenze
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt

Su Windows al posto di python si usa spesso il launcher py. Se pip non si trova, lo installa il modulo integrato: python -m ensurepip --upgrade.

Librerie Python più diffuse

Su PyPI ci sono centinaia di migliaia di pacchetti, ma nella maggior parte dei progetti compare sempre la stessa breve lista. Conviene partire da essa, invece di cercare soluzioni esotiche.

CompitoLibrerie
Richieste HTTP e APIrequests, httpx
Analisi dei dati e tabellepandas, numpy
Graficimatplotlib
Servizi webfastapi, django, flask
Testpytest
Immaginipillow (si importa come PIL)

Attenzione: il nome per l'installazione e quello per l'import non sempre coincidono. Si installa pip install pillow, ma si scrive from PIL import Image; si installa opencv-python, ma si importa cv2. Se import fallisce subito dopo l'installazione, controllate nella documentazione del pacchetto con quale nome viene importato.

Installazione di librerie in Linux

Nelle versioni recenti di Debian e Ubuntu il comando pip install nel Python di sistema termina con l'errore externally-managed-environment (PEP 668). È una protezione: il Python di sistema appartiene al gestore pacchetti del sistema operativo e pip non deve romperlo. La soluzione giusta non è --break-system-packages, ma un ambiente virtuale.

venv in Python: ambiente virtuale

L'ambiente virtuale è una cartella separata con una propria copia dell'interprete (un collegamento ad esso) e un proprio site-packages. Le librerie installate lì sono visibili solo a quel progetto. Così un progetto può usare Django 4 e un altro Django 5 senza conflitti.

Il modulo venv è integrato in Python e non va installato a parte (su Debian/Ubuntu a volte serve il pacchetto di sistema python3-venv).

# creare l'ambiente nella cartella .venv
python -m venv .venv

# attivare: Linux e macOS
source .venv/bin/activate
# attivare: Windows PowerShell
.venv\Scripts\Activate.ps1

# ora pip installa i pacchetti dentro .venv
python -m pip install requests
python -c "import sys; print(sys.prefix)"

# uscire dall'ambiente
deactivate

Dopo l'attivazione all'inizio della riga del terminale compare (.venv). La cartella dell'ambiente non va salvata in git (aggiungete .venv/ a .gitignore) e non si copia da una macchina all'altra: al suo posto si conserva l'elenco delle dipendenze e l'ambiente si ricrea. Se PowerShell blocca lo script di attivazione, consentitene l'esecuzione per l'utente: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.

uv e pyproject.toml

I progetti moderni descrivono le dipendenze in pyproject.toml. Il gestore uv, usato nel corso, unisce la creazione dell'ambiente e l'installazione: uv add pandas scarica il pacchetto, lo scrive in pyproject.toml e fissa le versioni esatte in uv.lock. Il collega clona il progetto, esegue uv sync e ottiene un ambiente identico.

[project]
name = "spese"
version = "0.1.0"
requires-python = ">=3.15"
dependencies = [
    "pandas>=2.3",
]

[project.scripts]
spese = "spese.cli:main"

Lazy import in Python 3.15 (PEP 810)

La novità principale della 3.15 in questo argomento è la parola chiave lazy. Le librerie pesanti si caricano a lungo: nella misura fatta nel corso sull'immagine python:3.15-slim, un normale import pandas richiedeva circa 415 ms, mentre lazy import pandas circa 13 ms. Per un'utility da riga di comando che si avvia per mostrare --help, la differenza è enorme.

lazy import pandas as pd
lazy from spese.report import build_report

def main() -> None:
    ...
    df = pd.read_csv(path)   # il vero caricamento di pandas avviene qui

Al posto del modulo il nome riceve un oggetto proxy (types.LazyImportType), e il vero import avviene solo al primo utilizzo del nome. Se non si arriva mai a quel punto, il tempo non viene speso affatto.

Limiti del lazy import

  • È consentito solo al livello più alto del modulo: dentro una funzione, una classe o un try/except genera SyntaxError.
  • La forma lazy from x import * non è ammessa.
  • ModuleNotFoundError compare non all'avvio, ma al primo utilizzo.
  • Gli effetti collaterali del modulo (registrazione di plugin e simili) si spostano nel tempo.

Rendere pigri tutti gli import in un colpo solo si può con il flag -X lazy_imports=all o con la variabile PYTHON_LAZY_IMPORTS=all; le eccezioni si definiscono tramite sys.set_lazy_imports_filter(). Per il codice che deve funzionare anche sulle versioni vecchie c'è la variabile di modulo __lazy_modules__ = ["pandas"]: la 3.15 rende pigri gli import elencati, mentre le versioni precedenti eseguono semplicemente un normale import. Dove si perde tempo all'avvio lo mostra python -X importtime -c "import pandas". A guadagnarci sono soprattutto i programmi avviati spesso per brevi esecuzioni; un server di lunga durata ne trae quasi nulla.

Errori tipici

  • ModuleNotFoundError: No module named 'requests' — la libreria è stata installata in un altro Python oppure l'ambiente non è attivo. Controllate con python -m pip show requests usando lo stesso interprete.
  • Il vostro file si chiama json.py, random.py o csv.py — la cartella dello script è la prima in sys.path e il file copre il modulo standard. Python 3.13+ nell'errore suggerisce «consider renaming». Rinominate il file ed eliminate __pycache__.
  • Import circolare: a.py importa b.py, e questo importa a.py. Spostate il codice comune in un terzo modulo oppure importate dentro la funzione.
  • pip lanciato dentro l'interprete Python (>>> pip install) — genera SyntaxError. I comandi pip si eseguono nel terminale.

Conclusioni

Il modulo è un file, il pacchetto è una cartella di moduli, la libreria è il loro insieme pronto all'uso; import cerca il modulo nella cache e in sys.path e lo esegue una sola volta. Le librerie esterne si installano con pip o uv soltanto in un ambiente virtuale venv: così i progetti non si intralciano e l'ambiente si riproduce facilmente. Nel corso di Python questo argomento è trattato in pratica: il tracker delle spese diventa un pacchetto con dipendenze e si avvia rapidamente grazie ai lazy import.

Domande frequenti

Serve creare un venv per ogni progetto?

Sì, è una buona pratica: ogni progetto ha le proprie versioni delle librerie, e un ambiente separato evita conflitti e non sporca il Python di sistema.

In che cosa pip si differenzia da uv?

pip si limita a installare pacchetti, mentre uv crea anche l'ambiente, scrive le dipendenze in pyproject.toml e fissa le versioni esatte in un file di lock; inoltre è molto più veloce.

Come vedere l'elenco delle librerie installate in Python?

Eseguite python -m pip list nell'ambiente desiderato; pip freeze mostra lo stesso elenco nel formato di requirements.txt.

Dove sono salvati i moduli installati?

Nella cartella site-packages dell'ambiente attivo; il percorso di un singolo modulo lo mostra l'attributo __file__, per esempio import requests; print(requests.__file__).

Si può copiare la cartella venv su un altro computer?

No: l'ambiente è legato ai percorsi e all'interprete della macchina. Si trasferisce l'elenco delle dipendenze e l'ambiente si crea di nuovo.

Impara l’argomento in video

Questo argomento è trattato in modo approfondito, con pratica, nel corso «Python 3.15: от новичка до профи».

Vai al corso