Innanzitutto, tieni presente che, nella sua definizione precisa, un modulo è un oggetto nella memoria di un interprete Python, spesso creato leggendo uno o più file dal disco. Mentre possiamo chiamare in modo informale un file del disco come a/b/c.py
un "modulo", in realtà non lo diventa fino a quando non viene combinato con le informazioni provenienti da altre fonti (come sys.path
) per creare l'oggetto modulo.
(Si noti, ad esempio, che due moduli con nomi diversi possono essere caricati dallo stesso file, a seconda di sys.path
e altre impostazioni. Questo è esattamente ciò che accade python -m my.module
seguito da un import my.module
nell'interprete; ci saranno due oggetti modulo __main__
e my.module
, entrambi creati dallo stesso file su disco my/module.py
.)
Un pacchetto è un modulo che può avere sottomoduli (compresi i pacchetti secondari). Non tutti i moduli possono farlo. Ad esempio, crea una gerarchia di piccoli moduli:
$ mkdir -p a/b
$ touch a/b/c.py
Assicurarsi che non ci siano altri file sotto a
. Avvia un interprete Python 3.4 o successivo (ad es. Con python3 -i
) ed esamina i risultati delle seguenti affermazioni:
import a
a ⇒ <module 'a' (namespace)>
a.b ⇒ AttributeError: module 'a' has no attribute 'b'
import a.b.c
a.b ⇒ <module 'a.b' (namespace)>
a.b.c ⇒ <module 'a.b.c' from '/home/cjs/a/b/c.py'>
I moduli a
e a.b
sono pacchetti (in effetti, un certo tipo di pacchetto chiamato "pacchetto spazio dei nomi", anche se qui non ci preoccuperemo). Tuttavia, il modulo a.b.c
non è un pacchetto. Possiamo dimostrarlo aggiungendo un altro file, a/b.py
alla struttura di directory sopra e avviando un nuovo interprete:
import a.b.c
⇒ ImportError: No module named 'a.b.c'; 'a.b' is not a package
import a.b
a ⇒ <module 'a' (namespace)>
a.__path__ ⇒ _NamespacePath(['/.../a'])
a.b ⇒ <module 'a.b' from '/home/cjs/tmp/a/b.py'>
a.b.__path__ ⇒ AttributeError: 'module' object has no attribute '__path__'
Python assicura che tutti i moduli padre siano caricati prima che un modulo figlio sia caricato. Sopra trova che a/
è una directory e quindi crea un pacchetto dello spazio dei nomi a
e che a/b.py
è un file sorgente Python che carica e usa per creare un modulo (non-pacchetto) a.b
. A questo punto non puoi avere un modulo a.b.c
perchéa.b
non è un pacchetto, e quindi non puoi avere sottomoduli.
Puoi anche vedere qui che il modulo pacchetto a
ha un __path__
attributo (i pacchetti devono avere questo) ma il modulo a.b
non pacchetto no.