В чем разница между модулем Python и пакетом Python?

577

В чем разница между модулем Python и пакетом Python?

Смотрите также: В чем разница между "package" и "module" (для других языков)

Дейв
источник
9
Я могу ошибаться, но для меня: модуль в основном один файл Python. Пакет - это папка с кучей модулей (файлов Python).
lc2817
36
Чтобы считаться пакетом, эта папка должна содержать __init__.pyфайл.
Джулио Пьянкастелли
@ lc2817: это наиболее распространенный случай, но нет необходимости загружать модуль из файловой системы, например, см. from plumbum.cmd import lsреализацию
jfs
Как сообщество различает пакеты Python и пакеты, используемые для распространения таких компонентов Python, как PyPI / wheel / etc? Эти два слова кажутся мне различными применениями слова «пакет».
Давида

Ответы:

372

Модуль - это отдельный файл (или файлы), которые импортируются и используются при одном импорте. например

import my_module

Пакет - это набор модулей в каталогах, которые предоставляют иерархию пакетов.

from my_package.timing.danger.internets import function_of_love

Документация для модулей

Введение в пакеты

Якоб Бауэр
источник
54
Когда вы говорите: «Модуль - это один файл (или файлы), которые импортируются в рамках одного импорта», вы можете объяснить ситуацию, когда модуль представляет собой более одного файла? Или я неправильно понимаю, что вы имеете в виду?
Пользователь
6
Вам не нужен файл для создания модуля, например, вы можете импортировать модуль из zip-файла. То же самое для пакетов. В Python есть только один класс для модулей / пакетов. Пакет - это просто модуль с __path__атрибутом.
Jfs
33
Пакеты тоже модули . Они просто упакованы по-разному; они сформированы комбинацией каталога плюс __init__.pyфайл. Это модули, которые могут содержать другие модули.
Мартин Питерс
15
@ Я уверен, см. « Система импорта» в справочной документации: важно помнить, что все пакеты являются модулями .
Мартин Питерс
6
@Jacquot: и глоссарий «пакета» : модуль Python, который может содержать субмодули или рекурсивно, подпакеты. Технически пакет представляет собой модуль Python с __path__атрибутом.
Мартин Питерс
556

Любой файл Python является модулем , его имя является базовым именем файла без .pyрасширения. Пакет представляет собой набор модулей Python: в то время как модуль представляет собой один файл Python, пакет представляет собой каталог модулей Python , содержащих дополнительный __init__.pyфайл, чтобы отличить пакет из каталога , который только , случается, содержит набор сценариев Python. Пакеты могут быть вложены на любую глубину при условии, что соответствующие каталоги содержат свои собственные__init__.py файл.

Различие между модулем и пакетом, кажется, сохраняется только на уровне файловой системы. Когда вы импортируете модуль или пакет, соответствующий объект, созданный Python, всегда имеет тип module. Однако обратите внимание, что при импорте пакета __init__.pyнепосредственно видны только переменные / функции / классы в файле этого пакета, а не подпакеты или модули. В качестве примера рассмотримxml пакет в стандартной библиотеке Python: его xmlкаталог содержит __init__.pyфайл и четыре подкаталога; подкаталог etreeсодержит __init__.pyфайл и, среди прочего, ElementTree.pyфайл. Посмотрите, что происходит, когда вы пытаетесь интерактивно импортировать пакет / модули:

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

В Python также есть встроенные модули, такие как sysнаписанные на C, но я не думаю, что вы хотели рассмотреть те из них, которые у вас возникли.

Джулио Пьянкастелли
источник
9
Спасибо за явное упоминание, что соответствующий объект, созданный Python, всегда имеет тип module. Я нахожусь в процессе написания отладчика и беспокоился, что мой отладчик неверно сказал, что мои пакеты были modules.
ArtOfWarfare
8
@jolvi Файлы Python с именем файла, содержащим тире, все еще можно импортировать как модули, но не с помощью обычного importоператора, поскольку дефисы не допускаются в идентификаторах Python. Используйте importlib.import_module()вместо этого.
Джулио Пьянкастелли
2
@jolvi Я нет. Где в моем комментарии вы это читаете? Я просто говорю, что, если вы случайно наткнулись на файл Python с тире в его имени, вы все равно можете импортировать его как модуль. Я не делаю заявления о предпочтительном способе именования файла Python. Я уверен, что вы можете найти это где-то еще: обычно настоятельно рекомендуется избегать штрихов в пользу подчеркивания.
Джулио Пьянкастелли
3
Будучи новичком в Python, подпакеты или модули не были доступны по умолчанию при импорте родительского пакета, и это меня споткнуло. Есть ли для этого особая причина? И есть ли общая схема, как сделать доступными подпакеты или модули (через их полное имя) при импорте родительского пакета?
sschuberth
2
@sschuberth Просто импортируйте подпакеты в init .py родительского пакета.
Анна
33

Из глоссария Python :

Важно помнить, что все пакеты являются модулями, но не все модули являются пакетами. Или, другими словами, пакеты - это просто особый вид модуля. В частности, любой модуль, содержащий __path__атрибут, считается пакетом.

Файлы Python с тире в имени, например my-file.py, не могут быть импортированы с помощью простого importоператора. С точки зрения кода, import my-fileэто то же самое, import my - fileчто вызовет исключение. Такие файлы лучше охарактеризовать как скрипты, тогда как импортируемые файлы - это модули .

jolvi
источник
23

Во-первых, имейте в виду, что в своем точном определении модуль - это объект в памяти интерпретатора Python, который часто создается путем чтения одного или нескольких файлов с диска. Хотя мы можем неофициально называть дисковый файл, такой как a/b/c.py«модуль», он фактически не становится единым, пока не будет объединен с информацией из нескольких других источников (например, sys.path) для создания объекта модуля.

(Обратите внимание, например, что два модуля с разными именами могут быть загружены из одного и того же файла, в зависимости от sys.pathдругих настроек. Это именно то, что происходит с python -m my.moduleпоследующим import my.moduleв интерпретаторе; там будет два объекта модуля, __main__и my.moduleоба будут созданы из того же файла на диске,. my/module.py)

Пакет представляет собой модуль , который может иметь подмодули ( в том числе подпакетов). Не все модули могут сделать это. В качестве примера создайте небольшую иерархию модулей:

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

Убедитесь, что нет других файлов под a. Запустите интерпретатор Python 3.4 или более поздней python3 -iверсии (например, с помощью ) и проверьте результаты следующих утверждений:

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

Модули aи a.bявляются пакетами (на самом деле, это пакет определенного типа, называемый «пакет пространства имен», хотя мы не будем беспокоиться об этом здесь). Тем не менее, модуль a.b.cне является пакетом. Мы можем продемонстрировать это, добавив другой файл a/b.pyв структуру каталогов выше и запустив новый интерпретатор:

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 гарантирует, что все родительские модули загружаются до загрузки дочернего модуля. Выше он находит, что a/это каталог, и, таким образом, создает пакет пространства имен a, и a/b.pyэто исходный файл Python, который он загружает и использует для создания (не пакетного) модуля a.b. На данный момент вы не можете иметь модуль, a.b.cпотому чтоa.b он не является пакетом и, следовательно, не может иметь подмодулей.

Здесь вы также можете видеть, что у модуля пакета aесть __path__атрибут (у пакетов должен быть такой), а у модуля без пакета a.bего нет.

CJS
источник
1
Если вы еще этого не сделали, вернитесь назад и поработайте над примерами из этого ответа.
Донал Лафферти
2

Поздний ответ, еще одно определение:

Пакет представлен импортированной верхней сущностью, которая может быть либо автономным модулем, либо __init__.pyспециальным модулем в качестве верхней сущности из набора модулей в структуре подкаталога.

Таким образом, физически пакет представляет собой распределительный модуль, который предоставляет один или несколько модулей.

ACUE
источник
1
Я чувствую, что есть два определения для пакета в Python, и они различны. Ваш ответ, кажется, объединяет их вместе. Строго говоря, пакет python - это каталог с __init__.pyмодулем внутри, но если вы говорите о единицах распределения (обычно через PyPI), то это совершенно другой тип пакета (обычно определяемый существованием setup.py). Я нахожу эти два использования термина packageзапутывающими, и я говорил с некоторыми новичками Python, которые находят это совершенно изумительным.
Давида
@davidA, это не только то, что ты чувствуешь. Это было кодифицировано: packaging.python.org/glossary/#term-distribution-package (Спасибо за разъяснения тоже!)
Lorem Ipsum