¿Cuál es la diferencia entre un módulo Python y un paquete Python?

577

¿Cuál es la diferencia entre un módulo Python y un paquete Python?

Consulte también: ¿Cuál es la diferencia entre "paquete" y "módulo" (para otros idiomas)

Dave
fuente
99
Podría estar equivocado, pero para mí: un módulo es básicamente un archivo de Python. Un paquete es una carpeta con un montón de módulos (archivos python).
lc2817
36
Para ser considerado un paquete, esa carpeta debe contener un __init__.pyarchivo.
Giulio Piancastelli
@ lc2817: es el caso más común, pero no es necesario que se cargue un módulo desde un sistema de archivos, por ejemplo, vea from plumbum.cmd import lsimplementación
jfs
44
@GiulioPiancastelli: en Python 3.3+, los paquetes de espacio de nombres no se usan__init__.py
jfs
¿Cómo diferencia la comunidad entre los paquetes de Python y los paquetes utilizados para distribuir componentes de Python como PyPI / wheels / etc? Las dos me parecen aplicaciones diferentes de la palabra "paquete".
davidA

Respuestas:

372

Un módulo es un único archivo (o archivos) que se importan bajo una importación y se usan. p.ej

import my_module

Un paquete es una colección de módulos en directorios que dan una jerarquía de paquetes.

from my_package.timing.danger.internets import function_of_love

Documentación para módulos

Introducción a paquetes

Jakob Bowyer
fuente
54
Cuando dice: "Un módulo es un solo archivo (o archivos) que se importan bajo una importación", ¿puede explicar la situación en la que un módulo es más de un archivo? ¿O estoy interpretando mal lo que quieres decir?
Usuario
66
No necesita un archivo para crear un módulo, por ejemplo, podría importar un módulo desde un archivo zip. Lo mismo para los paquetes. Solo hay una clase para módulos / paquetes en Python. El paquete es solo un módulo con un __path__atributo.
jfs
33
Los paquetes también son módulos . Se empaquetan de manera diferente; están formados por la combinación de un directorio más un __init__.pyarchivo. Son módulos que pueden contener otros módulos.
Martijn Pieters
15
@Jacquot seguro, consulte El sistema de importación en la documentación de referencia: es importante tener en cuenta que todos los paquetes son módulos .
Martijn Pieters
66
@Jacquot: y el glosario sobre "paquete" : un módulo de Python que puede contener submódulos o recursivamente, subpaquetes. Técnicamente, un paquete es un módulo de Python con un __path__atributo.
Martijn Pieters
556

Cualquier archivo Python es un módulo , cuyo nombre es el nombre base del archivo sin la .pyextensión. Un paquete es una colección de módulos de Python: mientras que un módulo es un solo archivo de Python, un paquete es un directorio de módulos de Python que contiene un __init__.pyarchivo adicional , para distinguir un paquete de un directorio que simplemente contiene un montón de scripts de Python. Los paquetes se pueden anidar a cualquier profundidad, siempre que los directorios correspondientes contengan su propio __init__.pyarchivo.

La distinción entre módulo y paquete parece mantenerse solo en el nivel del sistema de archivos. Cuando importa un módulo o un paquete, el objeto correspondiente creado por Python siempre es de tipo module. Sin embargo, tenga en cuenta que cuando importa un paquete, solo las variables / funciones / clases en el __init__.pyarchivo de ese paquete son directamente visibles, no subpaquetes o módulos. Como ejemplo, considere el xmlpaquete en la biblioteca estándar de Python: su xmldirectorio contiene un __init__.pyarchivo y cuatro subdirectorios; el subdirectorio etreecontiene un __init__.pyarchivo y, entre otros, un ElementTree.pyarchivo. Vea lo que sucede cuando intenta importar paquetes / módulos de forma interactiva:

>>> 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>

En Python también hay módulos incorporados, como sys, que están escritos en C, pero no creo que quisieras considerarlos en tu pregunta.

Giulio Piancastelli
fuente
99
Gracias por mencionar explícitamente que el objeto correspondiente creado por Python siempre es de tipo module. Estoy en el proceso de escribir un depurador y me preocupaba que mi depurador fuera incorrecto al decir que mis paquetes eran modules.
ArtOfWarfare
8
@jolvi Los archivos de Python con un nombre de archivo que contiene guiones todavía se pueden importar como módulos, pero no con la importdeclaración habitual , porque los guiones no están permitidos en los identificadores de Python. Usar en su importlib.import_module()lugar.
Giulio Piancastelli
2
@jolvi no lo soy. ¿Dónde en mi comentario estás leyendo eso? Solo digo que, si tiene o se topa con un archivo de Python con guiones en su nombre, aún puede importarlo como un módulo. No estoy haciendo una declaración sobre la forma preferida de nombrar un archivo Python. Estoy seguro de que puede encontrarlo en otro lugar: generalmente se recomienda encarecidamente evitar guiones a favor de los guiones bajos.
Giulio Piancastelli
3
Ser nuevo en Python, los subpaquetes o módulos que no están disponibles de forma predeterminada al importar el paquete principal es lo que me hizo tropezar. ¿Hay alguna razón particular para eso? ¿Y hay un patrón común sobre cómo hacer que los subpaquetes o módulos estén disponibles (a través de su nombre completo) al importar el paquete principal?
sschuberth
2
@sschuberth Simplemente importe subpaquetes en init .py de un paquete primario.
Anna
33

Del glosario de Python :

Es importante tener en cuenta que todos los paquetes son módulos, pero no todos los módulos son paquetes. O dicho de otra manera, los paquetes son solo un tipo especial de módulo. Específicamente, cualquier módulo que contenga un __path__atributo se considera un paquete.

Los archivos Python con un guión en el nombre, como my-file.py, no pueden importarse con una simple importdeclaración. En cuanto al código, import my-filees lo mismo import my - fileque generará una excepción. Dichos archivos se caracterizan mejor como scripts, mientras que los archivos importables son módulos .

jolvi
fuente
23

Primero, tenga en cuenta que, en su definición precisa, un módulo es un objeto en la memoria de un intérprete de Python, a menudo creado al leer uno o más archivos del disco. Si bien podemos llamar informalmente un archivo de disco como a/b/c.pyun "módulo", en realidad no se convierte en uno hasta que se combina con información de varias otras fuentes (como sys.path) para crear el objeto del módulo.

(Tenga en cuenta, por ejemplo, que se pueden cargar dos módulos con nombres diferentes desde el mismo archivo, dependiendo de sys.pathy otras configuraciones. Esto es exactamente lo que sucede con python -m my.moduleseguido de un import my.moduleen el intérprete; habrá dos objetos de módulo __main__y my.module, ambos creados) del mismo archivo en el disco,. my/module.py)

Un paquete es un módulo que puede tener submódulos (incluidos los subpaquetes). No todos los módulos pueden hacer esto. Como ejemplo, cree una pequeña jerarquía de módulos:

$ mkdir -p a/b
$ touch a/b/c.py

Asegúrese de que no haya otros archivos debajo a. Inicie un intérprete Python 3.4 o posterior (por ejemplo, con python3 -i) y examine los resultados de las siguientes afirmaciones:

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'>

Módulos ay a.bpaquetes (de hecho, cierto tipo de paquete llamado "paquete de espacio de nombres", aunque no nos preocuparemos por eso aquí). Sin embargo, el módulo a.b.cno es un paquete. Podemos demostrar esto agregando otro archivo a/b.pya la estructura de directorios anterior e iniciando un nuevo intérprete:

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 asegura que todos los módulos principales se carguen antes de cargar un módulo secundario. Arriba encuentra que a/es un directorio y, por lo tanto, crea un paquete de espacio de nombres a, y que a/b.pyes un archivo fuente de Python que carga y usa para crear un módulo (sin paquete) a.b. En este punto, no puede tener un módulo a.b.cporque a.bno es un paquete y, por lo tanto, no puede tener submódulos.

También puede ver aquí que el módulo de paquete atiene un __path__atributo (los paquetes deben tener esto) pero el módulo sin paquete a.bno.

cjs
fuente
1
Si aún no lo ha hecho, regrese y analice los ejemplos en esta respuesta.
Donal Lafferty
2

Una respuesta tardía, otra definición más:

Un paquete está representado por una entidad superior importada que podría ser un módulo autónomo o el __init__.pymódulo especial como entidad superior de un conjunto de módulos dentro de una estructura de subdirectorio.

Entonces, físicamente un paquete es una unidad de distribución, que proporciona uno o más módulos.

acue
fuente
1
Siento que hay dos definiciones para paquete en Python y son distintas. Su respuesta parece combinarlos juntos. Estrictamente hablando, un paquete de Python es un directorio con un __init__.pymódulo dentro, pero si habla de unidades de distribución (comúnmente a través de PyPI), este es otro tipo de paquete completo (generalmente definido por la existencia de setup.py). Encuentro estos dos usos del término packageconfusos, y he hablado con algunos principiantes de Python que lo encuentran completamente desconcertante.
davidA
@davidA, no es solo cómo te sientes. Ha sido codificado: packaging.python.org/glossary/#term-distribution-package (¡Gracias por aclarar también!)
Lorem Ipsum el