На этом шаге мы рассмотрим особенности такого импортирования.
У вас есть упорядоченный в пакет код, и вы хотите импортировать подмодуль из одного из подмодулей другого пакета без прямого прописывания (hardcoding) имени пакета в инструкции импортирования.
Чтобы импортировать модули пакета из других модулей в том же пакете, используйте импортирование относительно пакета. Предположим, например, что у вас есть пакет mypackage, который организован следующим образом:
mypackage/
__init__.py
A/
__init__.py
spam.py
grok.py
В/
__init__.py
bar.py
Если модуль mypackage.A.spam пожелает импортировать модуль grok, размещенный в том же каталоге, он должен будет обзавестись такой инструкцией:
# mypackage/A/spam.py from . import grok
Если тот же модуль захочет импортировать модуль B.bar, размещенный в другом каталоге, вы можете использовать такую инструкцию:
# mypackage/A/spam.py from ..B import bar
Обе показанные инструкции импортирования работают относительно местоположения файла spam.py и не включают имя пакета высшего уровня.
Внутри пакетов при импортировании модулей того же пакета можно использовать либо полные абсолютные имена, либо относительное импортирование через показанный выше синтаксис. Например:
# mypackage/A/spam.py from mypackage.A import grok # ОК from . import grok # OK import grok # Ошибка (не найден)
Недостаток использования абсолютного имени, такого как mypackage.A, заключается в том, что оно напрямую прописывает имя пакета высшего уровня в исходный код. Это, в свою очередь, делает ваш код более хрупким и затрудняет работу по реорганизации. Например, если вы когда-либо захотите поменять имя пакета, вам придется пройтись по всем файлам и поправить исходный код. Похожим образом напрямую прописанные имена затрудняют перемещение кода. Например, если кто-то захочет установить две разные версии пакета, различающиеся только именами, то при использовании относительного импортирования все будет работать хорошо, но абсолютные имена не позволят этого сделать.
Синтаксис инструкции import . и .. может показаться забавным, но предлагаем вам думать о нем как об определении имени каталога. Символы .. означают "ищи в текущем каталоге", а ..B - "ищи в каталоге ../В". Этот синтаксис работает только с формой from. Например:
from . import grok # OK import . grok # Ошибка
Хотя это выглядит так, будто вы можете перемещаться по файловой системе через относительное импортирование, но на самом деле это не позволит вам выйти из каталога, в котором определен пакет. Это означает, что комбинирование имен с точками, которое заставляет производить импортирование из-за пределов пакета, вызовет ошибку.
Также стоит заметить, что относительное импортирование работает только для модулей, которые размещены внутри подходящего пакета. В частности, оно не работает внутри простых модулей, размещенных на верхнем уровне скриптов. Оно также не работает, если части пакета исполняются напрямую, как скрипты. Например:
% python3 mypackage/A/spam.py
# Относительное импортирование не работает
С другой стороны, если вы выполните предыдущий скрипт, передав в Python опцию -m, относительное импортирование будет работать правильно. Например:
% python3 -m mypackage.A.spam
# Относительное импортирование работает
На следующем шаге мы рассмотрим разделение модуля на несколько файлов.