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.pyun "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.pathe altre impostazioni. Questo è esattamente ciò che accade python -m my.moduleseguito da un import my.modulenell'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 ae a.bsono pacchetti (in effetti, un certo tipo di pacchetto chiamato "pacchetto spazio dei nomi", anche se qui non ci preoccuperemo). Tuttavia, il modulo a.b.cnon è un pacchetto. Possiamo dimostrarlo aggiungendo un altro file, a/b.pyalla 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 ae 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.cperchéa.b non è un pacchetto, e quindi non puoi avere sottomoduli.
Puoi anche vedere qui che il modulo pacchetto aha un __path__attributo (i pacchetti devono avere questo) ma il modulo a.bnon pacchetto no.