Qual è la differenza tra un modulo Python e un pacchetto Python?


577

Qual è la differenza tra un modulo Python e un pacchetto Python?

Vedi anche: Qual è la differenza tra "pacchetto" e "modulo" (per altre lingue)


9
Potrei sbagliarmi, ma per me: un modulo è sostanzialmente un file Python. Un pacchetto è una cartella con un gruppo di moduli (file Python).
lc2817,

36
Per essere considerata un pacchetto, quella cartella deve contenere un __init__.pyfile.
Giulio Piancastelli,

@ lc2817: è il caso più comune ma non è necessario che un modulo venga caricato da un file system, ad es. vedi from plumbum.cmd import lsimplementazione
jfs

4
@GiulioPiancastelli: in Python 3.3+, i pacchetti dello spazio dei nomi non usano__init__.py
jfs

In che modo la community distingue tra pacchetti Python e pacchetti utilizzati per distribuire componenti Python come PyPI / wheels / etc? I due sembrano diverse applicazioni della parola "pacchetto" per me.
David,

Risposte:


372

Un modulo è un singolo file (o file) che viene importato in un'unica importazione e utilizzato. per esempio

import my_module

Un pacchetto è una raccolta di moduli in directory che danno una gerarchia di pacchetti.

from my_package.timing.danger.internets import function_of_love

Documentazione per moduli

Introduzione ai pacchetti


54
Quando dici: "Un modulo è un singolo file (o file) che viene importato in un'unica importazione" puoi spiegare la situazione in cui un modulo è più di un file? O sto leggendo male cosa intendi?
Utente

6
Non è necessario un file per creare un modulo, ad esempio, è possibile importare un modulo da un file zip. Lo stesso vale per i pacchetti. Esiste una sola classe per moduli / pacchetti in Python. Il pacchetto è solo un modulo con un __path__attributo.
jfs,

33
Anche i pacchetti sono moduli . Sono semplicemente impacchettati in modo diverso; sono formati dalla combinazione di una directory più un __init__.pyfile. Sono moduli che possono contenere altri moduli.
Martijn Pieters

15
@Jacquot certo, vedere Il sistema di importazione nella documentazione di riferimento: è importante tenere presente che tutti i pacchetti sono moduli .
Martijn Pieters

6
@Jacquot: e il glossario su "pacchetto" : un modulo Python che può contenere sottomoduli o ricorsivamente, sotto-pacchetti. Tecnicamente, un pacchetto è un modulo Python con un __path__attributo.
Martijn Pieters

556

Qualsiasi file Python è un modulo , il cui nome è il nome di base del file senza .pyestensione. Un pacchetto è una raccolta di moduli Python: mentre un modulo è un singolo file Python, un pacchetto è una directory di moduli Python contenente un __init__.pyfile aggiuntivo , per distinguere un pacchetto da una directory che contiene solo un gruppo di script Python. I pacchetti possono essere nidificati a qualsiasi profondità, a condizione che le directory corrispondenti contengano le proprie__init__.py file.

La distinzione tra modulo e pacchetto sembra valere solo a livello di file system. Quando si importa un modulo o un pacchetto, l'oggetto corrispondente creato da Python è sempre di tipo module. Si noti, tuttavia, quando si importa un pacchetto, solo le variabili / funzioni / classi nel __init__.pyfile di quel pacchetto sono direttamente visibili, non sotto-pacchetti o moduli. Ad esempio, considera il xmlpacchetto nella libreria standard di Python: la sua xmldirectory contiene un __init__.pyfile e quattro sottodirectory; la sottodirectory etreecontiene un __init__.pyfile e, tra l'altro, un ElementTree.pyfile. Guarda cosa succede quando provi a importare in modo interattivo pacchetti / moduli:

>>> import xml
>>> type(xml)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'etree'
>>> import xml.etree
>>> type(xml.etree)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'ElementTree'
>>> import xml.etree.ElementTree
>>> type(xml.etree.ElementTree)
<type 'module'>
>>> xml.etree.ElementTree.parse
<function parse at 0x00B135B0>

In Python ci sono anche moduli incorporati, come sys, che sono scritti in C, ma non credo che intendessi considerare quelli nella tua domanda.


9
Grazie per aver menzionato esplicitamente che l'oggetto corrispondente creato da Python è sempre di tipo module. Sto scrivendo un debugger ed ero preoccupato che il mio debugger non fosse corretto nel dire che i miei pacchetti erano modules.
ArtOfWarfare il

8
@jolvi I file Python con un nome file contenente trattini possono comunque essere importati come moduli, ma non con la solita importistruzione, perché i trattini non sono consentiti negli identificatori Python. Usa importlib.import_module()invece.
Giulio Piancastelli,

2
@jolvi non lo sono. Dove lo stai leggendo nel mio commento? Sto solo dicendo che, se ti capita di imbatterti o inciampare in un file Python con trattini nel suo nome, puoi comunque importarlo come modulo. Non sto facendo una dichiarazione sul modo preferito di nominare un file Python. Sono sicuro che puoi trovarlo da qualche altra parte: di solito si consiglia vivamente di evitare trattini a favore dei caratteri di sottolineatura.
Giulio Piancastelli,

3
Essere nuovi in ​​Python, sotto-pacchetti o moduli non disponibili per impostazione predefinita durante l'importazione del pacchetto padre è ciò che mi ha fatto inciampare. C'è una ragione particolare per questo? Esiste un modello comune su come rendere disponibili sotto-pacchetti o moduli (tramite il loro nome completo) durante l'importazione del pacchetto principale?
sschuberth

2
@sschuberth Basta importare sotto-pacchetti in init .py di un pacchetto genitore.
Anna,

33

Dal glossario di Python :

È importante tenere presente che tutti i pacchetti sono moduli, ma non tutti i moduli sono pacchetti. O in altri termini, i pacchetti sono solo un tipo speciale di modulo. In particolare, qualsiasi modulo che contiene un __path__attributo è considerato un pacchetto.

I file Python con un trattino nel nome, come my-file.py, non possono essere importati con una semplice importistruzione. Per quanto riguarda il codice, import my-fileè lo stesso import my - fileche solleverà un'eccezione. Tali file sono meglio caratterizzati come script mentre i file importabili sono moduli .


23

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.


1
Se non lo hai già fatto, torna indietro e analizza gli esempi in questa risposta.
Donal Lafferty,

2

Una risposta tardiva, ancora un'altra definizione:

Un pacchetto è rappresentato da un'entità superiore importata che può essere un modulo autonomo o il __init__.pymodulo speciale come entità superiore da un insieme di moduli all'interno di una struttura di directory secondaria.

Quindi fisicamente un pacchetto è un'unità di distribuzione, che fornisce uno o più moduli.


1
Sento che ci sono due definizioni per pacchetto in Python e sono distinte. La tua risposta sembra combinarli insieme. A rigor di termini, un pacchetto python è una directory con un __init__.pymodulo all'interno, ma se si parla di unità di distribuzione (comunemente tramite PyPI), questo è un altro tipo di pacchetto interamente (solitamente definito dall'esistenza di setup.py). Trovo questi due usi del termine packageconfusi, e ho parlato con alcuni principianti di Python che lo trovano assolutamente sconcertante.
David,

@davidA, Non è solo come ti senti. È stato codificato: packaging.python.org/glossary/#term-distribution-package (Grazie anche per il chiarimento!)
Lorem Ipsum
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.