Для чего нужен файл init py

Обновлено: 06.07.2024

Файлы __init__.py необходимы, чтобы Python рассматривал каталоги как содержащие пакеты; это делается для того, чтобы предотвратить каталоги с общим именем, например string , от непреднамеренного скрытия допустимых модулей, которые происходят позже (глубже) на пути поиска модуля. В простейшем случае __init__.py может быть просто пустым файлом, но он также может выполнять код инициализации для пакета или устанавливать переменную __all__ , описанную ниже.

Что это означает: «это сделано для предотвращения непреднамеренного скрытия действительными модулями каталогов с общим именем, например, строки, которые встречаются позже в пути поиска модулей»? @CarlG Python ищет список каталогов для разрешения имен, например, в операторах импорта. Поскольку это может быть любой каталог, а конечный пользователь может добавить произвольные каталоги, разработчикам приходится беспокоиться о каталогах, которые имеют одинаковое имя с допустимым модулем Python, например, «string» в примере с документами. Чтобы облегчить это, он игнорирует каталоги, которые не содержат файл с именем _ _ init _ _.py (без пробелов), даже если он пуст. @ DarekNędza У вас что-то настроено неправильно, если вы не можете просто открыть интерпретатор Python и без ошибок вывести from datetime import datetime . Это хорошо, вплоть до версии 2.3! @ DarekNędza В этом случае ImportError является допустимым выводом, потому что файл datetime.py, который мы вставили, пуст и не имеет определения для datetime. Импорт был успешным, как только я поместил класс datetime в файл. @ Двухразрядный Алхимик, ваша ссылка на документы и объяснения были полезны, но это оставляет вопрос без ответа. Почему у меня может быть каталог только с одним модулем "mymodule.py", который содержит определение функции "myfunc ()", и когда я открываю интерпретатор Python и набираю "import from mymodule myfunc", он не кинь ошибку. В каталоге отсутствует файл init .py, но все равно корректно импортируется mymodule. Он всегда просматривает текущий рабочий каталог процесса оболочки, независимо от того, является ли он модулем. Как правило, такие программы работают и не имеют ничего общего с системой import . Я не то, что вы, ребята, делаете, но суть пакетов в том, что такие модули, как html.parser и email.parser и dateutil.parser имеют уникальные имена, а не просто parser @loki Не могли бы вы переместить соответствующие части комментариев в свой пост? Гораздо сложнее следить за кучей комментариев, чем хорошо отредактированный пост. Можно ли просто сказать, что в каждом каталоге, кроме каталога верхнего уровня, должен быть файл __init.py__ ? Мне потребовалось много экспериментов, чтобы понять, что я должен удалить самый верхний уровень! @AaronMcDaid - почему? что произойдет, если у вас тоже есть один в верхней? Благодарю. Если мы хотим from abc import f , то есть файл a/b/c.py Внутри папки a , а также внутри папки a/b должен быть __init__.py . Там не должно быть никаких других __init__.py . Например, если он находится в вашем домашнем каталоге ( /home/username/a/b/c.py ) и вы создали /home/username/__init__.py , то вам потребуется from username.abc import f . По сути, каждый каталог, содержащий __init__.py должен быть назван в пути импорта Теперь, так как Python3 сделал __init__.py необязательным, я предполагаю, что случайно замаскировать string или datetime и время просто, или они предложили какой-то другой способ избежать этого?

Файлы с именем __init__.py используются для маркировки каталогов на диске в виде каталогов пакетов Python. Если у вас есть файлы

и mydir находится на вашем пути, вы можете импортировать код в module.py как

Если вы удалите файл __init__.py , Python больше не будет искать подмодули внутри этого каталога, поэтому попытки импортировать модуль не удастся.

Файл __init__.py обычно пуст, но может использоваться для экспорта выбранных частей пакета под более удобным именем, удержания функций удобства и т.д. В приведенном выше примере содержимое модуля init можно получить как

В дополнение к маркировке каталога как пакета Python и определению __all__ , __init__.py позволяет вам определять любую переменную на уровне пакета.. Это часто удобно, если пакет определяет что-то которые будут импортироваться часто, по API-подобным образом. Эта закономерность способствует соблюдению философии "плоской лучше, чем вложенной" в питоновскую философию.

Пример

Вот пример из одного из моих проектов, в котором я часто импортирую sessionmaker под названием Session для взаимодействия с моей базой данных. Я написал пакет "database" с несколькими модулями:

My __init__.py содержит следующий код:

Так как я определяю Session здесь, я могу начать новый сеанс, используя синтаксис ниже. Этот код был бы таким же выполненным изнутри или вне каталога пакета базы данных.

Конечно, это небольшое удобство - альтернативой было бы определить Session в новом файле типа "create_session.py" в моем пакете базы данных и начать новые сеансы, используя:

Дальнейшее чтение

Существует довольно интересная красноватая нить, охватывающая соответствующие применения __init__.py здесь:

По мнению большинства, файлы __init__.py должны быть очень тонкими, чтобы не нарушать "явную, лучше неявную" философию.

engine , sessionmaker , create_engine и os теперь также можно импортировать из database . похоже, вы запутались в этом пространстве имен. @ArtOfWarfare, вы можете использовать __all__ = [. ] чтобы ограничить то, что импортируется при import * . Но кроме этого, да, у вас осталось грязное пространство имен верхнего уровня.

Есть две основные причины для __init__.py

Для удобства: другим пользователям не нужно знать точное местоположение ваших функций в иерархии пакетов.

то другие могут вызвать add() на

без знания файла1, например

Если вы хотите, чтобы что-то было инициализировано; например, каротаж (который должен быть помещен на верхний уровень):

о, прежде чем читать ваш ответ, я подумал, что вызов функции явно из ее местоположения - хорошая практика.

Файл __init__.py позволяет каталогам Python обрабатывать их как модули.

Кроме того, это первый файл, который нужно загрузить в модуле, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз при загрузке модуля, или указать подмодули, которые будут экспортированы.

В Python определение пакета очень просто. Подобно Java, иерархическая структура и структура каталогов одинаковы. Но вы должны иметь __init__.py в пакете. Я объясню файл __init__.py следующим примером:

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

Если мы добавим функцию в module_n1:

Затем мы выполнили пакет иерархии и вызвали функцию module_n1. Мы можем использовать __init__.py в subPackage_b следующим образом:

Следовательно, используя * importing, пакет модулей подчиняется __init__.py контенту.

Так как Python 3.3, __init__.py больше не требуется определять каталоги как импортируемые пакеты Python.

Встроенная поддержка каталогов пакетов, для которых не требуются файлы маркеров __init__.py , и может автоматически охватывать несколько сегментов маршрута (вдохновленные различными сторонними подходами к пакетам пространства имен, как описано в PEP 420)

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

Для людей, которые предпочитают читать код, я помещаю комментарий Двубичный алхимик.

Он облегчает импорт других файлов python. Когда вы помещаете этот файл в каталог (например, материал), содержащий другие файлы py, вы можете сделать что-то вроде import stuff.other.

Без этого __init__.py внутри содержимого каталога вы не можете импортировать файл other.py, потому что Python не знает, где исходный код для материала и не может распознать его как пакет.

У меня есть та же структура в моем проекте (Python 3.4), но я не могу заставить другой файл увидеть другой файл. Как мне сделать импорт? из root.stuff импортировать другие? Он работает в режиме отладки VSCode, но не в командной строке. Есть идеи?

Что такое __init__.py, используемый для?

Основное использование __init__.py - инициализация пакетов Python. Самый простой способ продемонстрировать это - взглянуть на структуру стандартного модуля Python.

Как вы можете видеть в структуре выше включение файла __init__.py в каталог указывает интерпретатору Python, что каталог должен рассматриваться как пакет Python

Что происходит в __init__.py ?

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

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

В приведенном выше примере мы можем сказать, что file.py имеет файл класса. Таким образом, без чего-либо в нашем __init__.py вы импортируете этот синтаксис:

Однако вы можете импортировать File в свой __init__.py , чтобы сделать его доступным на уровне пакета:

Еще одна вещь, которую нужно сделать, это на уровне пакета сделать подпакеты/модули доступными с переменной __all__ . Когда интерпретатор видит переменную __all__ , определенную в __init__.py , она импортирует модули, перечисленные в переменной __all__ , когда вы делаете:

__all__ - это список, содержащий имена модулей, которые вы хотите импортировать с импортом *, так что снова просмотрев наш вышеприведенный пример, если мы хотим импортировать подмодули в подпакет, переменная __all__ в subpackage/__init__.py будет

С переменной __all__ , заполненной таким образом, когда вы выполняете

он импортирует подмодуль1 и подмодуль2.

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

Python определяет два типа пакетов, обычные пакеты и пакеты пространства имен. Обычные пакеты - это традиционные пакеты, которые существовали в Python 3.2 и более ранних версиях. Обычный пакет обычно реализуется как каталог, содержащий файл __init__.py . Когда импортируется обычный пакет, этот файл __init__.py выполняется неявно, а определяемые им объекты привязываются к именам в пространстве имен пакета. Файл __init__.py может содержать тот же код Python, что и любой другой модуль, и Python добавит некоторые дополнительные атрибуты в модуль при его импорте.

Но просто нажмите на ссылку, она содержит пример, дополнительную информацию и объяснение пакетов пространства имен, типа пакетов без __init__.py .

Файл __init__.py позволяет Python обрабатывать каталоги, содержащие его, как модули.

Кроме того, это первый файл, который будет загружен в модуль, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз при загрузке модуля, или указывать субмодули для экспорта.

Это облегчает импорт других файлов Python. Когда вы помещаете этот файл в каталог (скажем, вещи), содержащий другие файлы py, вы можете сделать что-то вроде импорта stuff.other.

Без этого __init__.py внутри содержимого каталога вы не сможете импортировать other.py, потому что Python не знает, где находится исходный код материала, и не может распознать его как пакет.

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

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

В дополнение к маркировке каталога как пакета Python и определению __all__ , __init__.py позволяет вам определять любую переменную на уровне пакета. Это часто бывает удобно, если пакет определяет что-то, что будет часто импортироваться, в стиле API. Эта модель способствует приверженности питонской философии «квартира лучше вложенного».

Пример

Вот пример из одного из моих проектов, в котором я часто импортирую sessionmaker с именем Session для взаимодействия с моей базой данных. Я написал пакет базы данных с несколькими модулями:

Мой __init__.py содержит следующий код:

Поскольку я определяю Session здесь, я могу начать новый сеанс, используя синтаксис ниже. Этот код будет одинаково выполняться изнутри или снаружи каталога пакета «база данных».

Конечно, это небольшое удобство - альтернативой может быть определение Session в новом файле, таком как «create_session.py» в моем пакете базы данных, и запуск новых сеансов с использованием:

Дальнейшее чтение

Здесь есть довольно интересный поток reddit, рассказывающий о соответствующих применениях __init__.py :

Похоже, что большинство считает, что __init__.py файлы должны быть очень тонкими, чтобы не нарушать философию «явный лучше, чем неявный».

Файл __init__.py упрощает импорт. Когда __init__.py присутствует в пакете, функцию a() можно импортировать из файла b.py следующим образом:

Без этого, однако, вы не можете импортировать напрямую. Вы должны изменить системный путь:

В Python определение пакета очень просто. Как и в Java, иерархическая структура и структура каталогов одинаковы. Но вы должны иметь __init__.py в пакете. Я объясню файл __init__.py следующим примером:

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

Если мы добавим функцию в module_n1:

Затем мы последовали за пакетом иерархии и назвали module_n1 функцией. Мы можем использовать __init__.py в subPackage_b следующим образом:

Следовательно, используя * import, пакет модуля зависит от содержимого __init__.py .

Файлы с именем __init__.py используются для пометки каталогов на диске как каталогов пакетов Python. Если у вас есть файлы

И mydir находится на вашем пути, вы можете импортировать код в module.py как

Если вы удалите файл __init__.py , Python больше не будет искать подмодули внутри этого каталога, поэтому попытки импортировать модуль будут неудачными.

Файл __init__.py обычно пуст, но его можно использовать для экспорта выбранных частей пакета под более удобным именем, хранения вспомогательных функций и т. Д. Учитывая приведенный выше пример, к содержимому модуля init можно получить доступ как

Хотя Python работает без файла __init__.py , вы все равно должны включить его.

Он указывает, что пакет должен рассматриваться как модуль, поэтому включайте его (даже если он пуст).

В некоторых случаях вы можете использовать __init__.py файл:

Представьте, что у вас была следующая файловая структура:

И methods.py содержал это:

Чтобы использовать foo() , вам понадобится одно из следующих:

Возможно, вам нужно (или вы хотите) сохранить methods.py внутри main_methods (например, среды выполнения / зависимости), но вы хотите импортировать только main_methods .

Если вы изменили имя methods.py на __init__.py , вы можете использовать foo() , просто импортировав main_methods :

Это работает, потому что __init__.py рассматривается как часть пакета.

Некоторые пакеты Python действительно делают это. Примером может служить JSON, где запущенный import json фактически импортирует < > из пакета json (см. Здесь структуру файла пакета) ) :

Исходный код: Lib/json/__init__.py

Начиная с Python 3.3, __init__.py больше не требуется для определения каталогов как импортируемых пакетов Python.

Встроенная поддержка каталогов пакетов, для которых не требуются файлы маркеров __init__.py и которые могут автоматически охватывать несколько сегментов пути (вдохновленные различными сторонними подходами к пакетам пространства имен, как описано в PEP 420)

Порой бывает трудно правильно реализовать import с первого раза, особенно если мы хотим добиться правильной работы на плохо совместимых между собой версиях Python 2 и Python 3. Попытаемся разобраться, что из себя представляют импорты в Python и как написать решение, которое подойдёт под обе версии языка.

Содержание

Ключевые моменты

  • Выражения import производят поиск по списку путей в sys.path .
  • sys.path всегда включает в себя путь скрипта, запущенного из командной строки, и не зависит от текущей рабочей директории.
  • Импортирование пакета по сути равноценно импортированию __init__.py этого пакета.

Основные определения

  • Модуль: любой файл *.py . Имя модуля — имя этого файла.
  • Встроенный модуль: «модуль», который был написан на Си, скомпилирован и встроен в интерпретатор Python, и потому не имеет файла *.py .
  • Пакет: любая папка, которая содержит файл __init__.py . Имя пакета — имя папки.
    • С версии Python 3.3 любая папка (даже без __init__.py ) считается пакетом.

    Пример структуры директорий

    Обратите внимание, что в корневой папке test/ нет файла __init__.py .

    Что делает import

    При импорте модуля Python выполняет весь код в нём. При импорте пакета Python выполняет код в файле пакета __init__.py , если такой имеется. Все объекты, определённые в модуле или __init__.py , становятся доступны импортирующему.

    Встроенные функции Python: какие нужно знать и на какие не стоит тратить время

    Основы import и sys.path

    Вот как оператор import производит поиск нужного модуля или пакета согласно документации Python:

    • директории, содержащей исходный скрипт (или текущей директории, если файл не указан);
    • директории по умолчанию, которая зависит от дистрибутива Python;
    • PYTHONPATH (список имён директорий; имеет синтаксис, аналогичный переменной окружения PATH ).

    Технически документация не совсем полна. Интерпретатор будет искать не только файл (модуль) spam.py , но и папку (пакет) spam .

    Обратите внимание, что Python сначала производит поиск среди встроенных модулей — тех, которые встроены непосредственно в интерпретатор. Список встроенных модулей зависит от дистрибутива Python, а найти этот список можно в sys.builtin_module_names (Python 2 и Python 3). Обычно в дистрибутивах есть модули sys (всегда включён в дистрибутив), math , itertools , time и прочие.

    В отличие от встроенных модулей, которые при поиске проверяются первыми, остальные (не встроенные) модули стандартной библиотеки проверяются после директории запущенного скрипта. Это приводит к сбивающему с толку поведению: возможно «заменить» некоторые, но не все модули стандартной библиотеки. Допустим, модуль math является встроенным модулем, а random — нет. Таким образом, import math в start.py импортирует модуль из стандартной библиотеки, а не наш файл math.py из той же директории. В то же время, import random в start.py импортирует наш файл random.py .

    25–26 ноября, Москва и онлайн, От 24 000 до 52 000 ₽

    Кроме того, импорты в Python регистрозависимы: import Spam и import spam — разные вещи.

    Функцию pkgutil.iter_modules() (Python 2 и Python 3) можно использовать, чтобы получить список всех модулей, которые можно импортировать из заданного пути:

    Чуть подробнее о sys.path

    Чтобы увидеть содержимое sys.path , запустите этот код:

    Документация Python описывает sys.path так:

    Список строк, указывающих пути для поиска модулей. Инициализируется из переменной окружения PYTHONPATH и директории по умолчанию, которая зависит от дистрибутива Python.

    При запуске программы после инициализации первым элементом этого списка, path[0] , будет директория, содержащая скрипт, который был использован для вызова интерпретатора Python. Если директория скрипта недоступна (например, если интерпретатор был вызван в интерактивном режиме или скрипт считывается из стандартного ввода), то path[0] является пустой строкой. Из-за этого Python сначала ищет модули в текущей директории. Обратите внимание, что директория скрипта вставляется перед путями, взятыми из PYTHONPATH .

    Источник: Python 2 и Python 3

    Документация к интерфейсу командной строки Python добавляет информацию о запуске скриптов из командной строки. В частности, при запуске python <script>.py .

    Если имя скрипта ссылается непосредственно на Python-файл, то директория, содержащая этот файл, добавляется в начало sys.path , а файл выполняется как модуль main .

    Источник: Python 2 и Python 3

    Итак, повторим порядок, согласно которому Python ищет импортируемые модули:

    1. Модули стандартной библиотеки (например, math , os ).
    2. Модули или пакеты, указанные в sys.path :
        1. Если интерпретатор Python запущен в интерактивном режиме:
          • sys.path[0] — пустая строка '' . Это значит, что Python будет искать в текущей рабочей директории, из которой вы запустили интерпретатор. В Unix-системах эту директорию можно узнать с помощью команды pwd .

        Если мы запускаем скрипт командой python <script>.py :

        Обратите внимание, что при запуске скрипта для sys.path важна не директория, в которой вы находитесь, а путь к самому скрипту. Например, если в командной строке мы находимся в test/folder и запускаем команду python ./packA/subA/subA1.py , то sys.path будет включать в себя test/packA/subA/ , но не test/ .

        Кроме того, sys.path общий для всех импортируемых модулей. Допустим, мы вызвали python start.py . Пусть start.py импортирует packA.a1 , а a1.py выводит на экран sys.path . В таком случае sys.path будет включать test/ (путь к start.py ), но не test/packA (путь к a1.py ). Это значит, что a1.py может вызвать import other , так как other.py находится в test/ .

        Всё о __init__.py

        У файла __init__.py есть две функции:

        1. Превратить папку со скриптами в импортируемый пакет модулей (до Python 3.3).
        2. Выполнить код инициализации пакета.

        Превращение папки со скриптами в импортируемый пакет модулей

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

        Как было сказано ранее, любая директория, содержащая файл __init__.py , является пакетом. Например, при работе с Python 2.7 start.py может импортировать пакет packA , но не packB , так как в директории test/packB/ нет файла __init__.py .

        Это не относится к Python 3.3 и выше благодаря появлению неявных пакетов пространств имён. Проще говоря, в Python 3.3+ все папки считаются пакетами, поэтому пустые файлы __init__.py больше не нужны.

        Допустим, packB — пакет пространства имён, так как в нём нет __init__.py . Если запустить интерактивную оболочку Python 3.6 в директории test/ , то мы увидим следующее:

        Выполнение кода инициализации пакета

        В момент, когда пакет или один из его модулей импортируется в первый раз, Python выполняет __init__.py в корне пакета, если такой файл существует. Все объекты и функции, определённые в __init__.py , считаются частью пространства имён пакета.

        Рассмотрим следующий пример:

        Вывод после запуска python start.py :

        Примечание Если a1.py вызовет import a2 , и мы запустим python a1.py , то test/packA/__init__.py не будет вызван, несмотря на то, что a2 вроде бы является частью пакета packA . Это связано с тем, что когда Python выполняет скрипт (в данном случае a1.py ), содержащая его папка не считается пакетом.

        Использование объектов из импортированного модуля или пакета

        Есть 4 разных вида импортов:

        1. import <пакет>
        2. import <модуль>
        3. from <пакет> import <модуль или подпакет или объект>
        4. from <модуль> import <объект>

        Пусть X — имя того, что идёт после import :

        • Если X — имя модуля или пакета, то для того, чтобы использовать объекты, определённые в X , придётся писать X.объект .
        • Если X — имя переменной, то её можно использовать напрямую.
        • Если X — имя функции, то её можно вызвать с помощью X() .

        Опционально после любого выражения import X можно добавить as Y . Это переименует X в Y в пределах скрипта. Учтите, что имя X с этого момента становится недействительным. Частым примером такой конструкции является import numpy as np .

        Аргументом для import может быть как одно имя, так и их список. Каждое из имён можно переименовать с помощью as . Например, следующее выражение будет действительно в start.py : import packA as pA, packA.a1, packA.subA.sa1 as sa1 .

        Пример: нужно в start.py импортировать функцию helloWorld() из sa1.py .

        • Решение 1: from packA.subA.sa1 import helloWorld . Мы можем вызвать функцию напрямую по имени: x = helloWorld() .
        • Решение 2: from packA.subA import sa1 или то же самое import packA.subA.sa1 as sa1 . Для использования функции нам нужно добавить перед её именем имя модуля: x = sa1.helloWorld() . Иногда такой подход предпочтительнее первого, так как становится ясно, из какого модуля взялась та или иная функция.
        • Решение 3: import packA.subA.sa1 . Для использования функции перед её именем нужно добавить полный путь: x = packA.subA.sa1.helloWorld() .

        Прим. перев. После переименования с помощью as новое имя нельзя использовать в качестве имени пакета или модуля для последующих импортов. Иными словами, команда вроде следующей недействительна: import packA as pA, pA.a1 .

        Используем dir() для исследования содержимого импортированного модуля

        После импортирования модуля можно использовать функцию dir() для получения списка доступных в модуле имён. Допустим, мы импортируем sa1 . Если в sa1.py есть функция helloWorld() , то dir(sa1) будет включать helloWorld :

        Импортирование пакетов

        Импортирование пакета по сути равноценно импортированию его __init__.py . Вот как Python на самом деле видит пакет:

        После импорта становятся доступны только те объекты, что определены в __init__.py пакета. Поскольку в packB нет такого файла, от import packB (в Python 3.3.+) будет мало толку, так как никакие объекты из этого пакета не становятся доступны. Последующий вызов модуля packB.b1 приведёт к ошибке, так как он ещё не был импортирован.

        Абсолютный и относительный импорт

        При абсолютном импорте используется полный путь (от начала корневой папки проекта) к желаемому модулю.

        При относительном импорте используется относительный путь (начиная с пути текущего модуля) к желаемому модулю. Есть два типа относительных импортов:

        1. При явном импорте используется формат from .<модуль/пакет> import X , где символы точки . показывают, на сколько директорий «вверх» нужно подняться. Одна точка . показывает текущую директорию, две точки .. — на одну директорию выше и т. д.
        2. Неявный относительный импорт пишется так, как если бы текущая директория была частью sys.path . Такой тип импортов поддерживается только в Python 2.

        В документации Python об относительных импортах в Python 3 написано следующее:

        Единственный приемлемый синтаксис для относительных импортов — from .[модуль] import [имя] . Все импорты, которые начинаются не с точки . , считаются абсолютными.

        Источник: What’s New in Python 3.0

        В качестве примера допустим, что мы запускаем start.py , который импортирует a1 , который импортирует other , a2 и sa1 . Тогда импорты в a1.py будут выглядеть следующим образом:

        Явные относительные импорты:

        Неявные относительные импорты (не поддерживаются в Python 3):

        Учтите, что в относительных импортах с помощью точек . можно дойти только до директории, содержащей запущенный из командной строки скрипт (не включительно). Таким образом, from .. import other не сработает в a1.py . В результате мы получим ошибку ValueError: attempted relative import beyond top-level package .

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

        Имейте в виду, что относительные импорты основаны на имени текущего модуля. Так как имя главного модуля всегда "__main__" , модули, которые должны использоваться как главный модуль приложения, должны всегда использовать абсолютные импорты.

        Источник: Python 2 и Python 3

        Примеры

        Пример 1: sys.path известен заранее

        Если вы собираетесь вызывать только python start.py или python other.py , то прописать импорты всем модулям не составит труда. В данном случае sys.path всегда будет включать папку test/ . Таким образом, все импорты можно писать относительно этой папки.

        Пример: файлу в проекте test нужно импортировать функцию helloWorld() из sa1.py .

        Решение: from packA.subA.sa1 import helloWorld (или любой другой эквивалентный синтаксис импорта).

        Пример 2: sys.path мог измениться

        Зачастую нам требуется как запускать скрипт напрямую из командной строки, так и импортировать его как модуль в другом скрипте. Как вы увидите далее, здесь могут возникнуть проблемы, особенно в Python 3.

        Пример: пусть start.py нужно импортировать a2 , которому нужно импортировать sa2 . Предположим, что start.py всегда запускается напрямую, а не импортируется. Также мы хотим иметь возможность запускать a2 напрямую.

        Звучит просто, не так ли? Нам всего лишь нужно выполнить два импорта: один в start.py и другой в a2.py .

        Проблема: это один из тех случаев, когда sys.path меняется. Когда мы выполняем start.py , sys.path содержит test/ , а при выполнении a2.py sys.path содержит test/packA/ .

        С импортом в start.py нет никаких проблем. Так как этот модуль всегда запускается напрямую, мы знаем, что при его выполнении в sys.path всегда будет test/ . Тогда импортировать a2 можно просто с помощью import packA.a2 .

        С импортом в a2.py немного сложнее. Когда мы запускаем start.py напрямую, sys.path содержит test/ , поэтому в a2.py импорт будет выглядеть как from packA.subA import sa2 . Однако если запустить a2.py напрямую, то в sys.path уже будет test/packA/ . Теперь импорт вызовет ошибку, так как packA не является папкой внутри test/packA/ .

        Вместо этого мы могли бы попробовать from subA import sa2 . Это решает проблему при запуске a2.py напрямую, однако теперь создаёт проблему при запуске start.py . В Python 3 это приведёт к ошибке, потому что subA не находится в sys.path (в Python 2 это не вызовет проблемы из-за поддержки неявных относительных импортов).

        Запускаем from packA.subA import sa2 from subA import sa2
        start.py Нет проблем В Py2 нет проблем, в Py3 ошибка ( subA не в test/ )
        a2.py Ошибка ( packA не в test/packA/ ) Нет проблем

        Использование относительного импорта from .subA import sa2 будет иметь тот же эффект, что и from packA.subA import sa2 .

        Вряд ли для этой проблемы есть чистое решение, поэтому вот несколько обходных путей:

        1. Использовать абсолютные импорты относительно директории test/ (т. е. средняя колонка в таблице выше). Это гарантирует, что запуск start.py напрямую всегда сработает. Чтобы запустить a2.py напрямую, запустите его как импортируемый модуль, а не как скрипт:

        1. В консоли смените директорию на test/ .
        2. Запустите python -m packA.a2 .

        2. Использовать абсолютные импорты относительно директории test/ (средняя колонка в таблице). Это гарантирует, что запуск start.py напрямую всегда сработает. Чтобы запустить a2.py напрямую, можно изменить sys.path в a2.py , чтобы включить test/packA/ перед импортом sa2 .

        Примечание Обычно этот метод работает, однако в некоторых случаях переменная __file__ может быть неправильной. В таком случае нужно использовать встроенный пакет inspect . Подробнее в этом ответе на StackOverflow.

        3. Использовать только Python 2 и неявные относительные импорты (последняя колонка в таблице).

        4. Использовать абсолютные импорты относительно директории test/ и добавить её в переменную среды PYTHONPATH . Это решение не переносимо, поэтому лучше не использовать его. О том, как добавить директорию в PYTHONPATH , читайте в этом ответе.

        Пример 3: sys.path мог измениться (вариант 2)

        А вот ещё одна проблема посложнее. Допустим, модуль a2.py никогда не надо запускать напрямую, но он импортируется start.py и a1.py , которые запускаются напрямую.

        В этом случае первое решение из примера выше не сработает. Тем не менее, всё ещё можно использовать остальные решения.

        Пример 4: импорт из родительской директории

        Если мы не изменяем PYTHONPATH и стараемся не изменять sys.path программно, то сталкиваемся со следующим основным ограничением импортов в Python: при запуске скрипта напрямую невозможно импортировать что-либо из его родительской директории.

        Например, если бы нам пришлось запустить python sa1.py , то этот модуль не смог бы ничего импортировать из a1.py без вмешательства в PYTHONPATH или sys.path .

        На первый взгляд может показаться, что относительные импорты (например from .. import a1 ) помогут решить эту проблему. Однако запускаемый скрипт (в данном случае sa1.py ) считается «модулем верхнего уровня». Попытка импортировать что-либо из директории над этим скриптом приведёт к ошибке ValueError: attempted relative import beyond top-level package .

        Для решения этой проблемы лучше её не создавать и избегать написания скриптов, которые импортируют из родительской директории. Если этого нельзя избежать, то предпочтительным обходным путём является изменение sys.path .

        Python 2 vs Python 3

        Мы разобрали основные отличия импортов в Python 2 и Python 3. Они ещё раз изложены здесь наряду с менее важными отличиями:

        Это часть пакета. вот документация.

        Файлы __init__.py необходимы для того, чтобы Python рассматривал каталоги как содержащие пакеты; это делается для предотвращения непреднамеренного сокрытия допустимых модулей, которые встречаются позже (глубже) в пути поиска модуля. В простейшем случае __init__.py может быть просто пустым файлом, но он также может выполнить код инициализации для пакета или задать переменную __all__ , описанную выше. позже.

        Файлы с именем __init__.py используются для обозначения каталогов на диске как каталогов пакетов Python. Если у вас есть файлы

        И mydir находится на вашем пути, вы можете импортировать код в module.py как

        Или

        Если вы удалите файл __init__.py , Python больше не будет искать подмодули в этом каталоге, поэтому попытки импортировать модуль завершатся неудачей.

        Файл __init__.py обычно пуст, но может быть использован для экспорта выбранных частей пакета под более удобное имя, функции удержания удобства и т. д. В приведенном выше примере содержимое модуля init можно получить в виде

        На основе этого

        В дополнение к маркировке каталога как пакета Python и определению __all__ , __init__.py позволяет определить любую переменную на уровне пакета. это часто удобно, если пакет определяет что-то, что будет импортироваться часто, подобно API. Этот паттерн способствует приверженности питоновской философии "плоское лучше вложенного".

        Пример

        Вот пример из одного из моих проектов, в котором я часто импортирую sessionmaker под названием Session в взаимодействуйте с моей базой данных. Я написал пакет "база данных" с несколькими модулями:

        Мой __init__.py содержит следующий код:

        Поскольку я определяю Session здесь, я могу начать новый сеанс, используя синтаксис ниже. Этот код будет таким же, выполняемым изнутри или снаружи каталога пакета "database".

        Конечно, это небольшое удобство - альтернативой было бы определить Session в новом файле типа "create_session.py - в моем пакете базы данных, и начните новые сеансы, используя:

        Дальнейшее чтение

        Есть довольно интересная нить reddit, охватывающая соответствующие применения __init__.py здесь:

        Http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

        Большинство считает, что файлы должны быть очень тонкими, чтобы не нарушать философию" явное лучше, чем неявное".
        1. Для удобства: другим пользователям не нужно будет знать точное расположение ваших функций в иерархии пакетов.

          Тогда другие могут вызвать add () с помощью

          Не зная file1, как

        2. Если вы хотите, чтобы что-то было инициализировано; например, ведение журнала (который должен быть помещен на верхний уровень):

        Файл __init__.py заставляет Python рассматривать каталоги, содержащие его, как модули.

        Кроме того, это первый файл, загружаемый в модуль, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз, когда модуль загружается, или указать подмодули, подлежащие экспорту.

        Поскольку Python 3.3, __init__.py больше не требуется определять каталоги как импортируемые пакеты Python.

        Check PEP 420: неявные пакеты пространства имен :

        Встроенная поддержка каталогов пакетов, которые не требуют __init__.py файлов маркеров и могут автоматически охватывать несколько сегментов пути (вдохновленные различными сторонними подходами к пакетам пространств имен, как описано в PEP 420)

        В Python определение пакета очень простое. Как и Java, иерархическая структура и структура каталогов одинаковы. Но вы должны иметь __init__.py в пакете. Я объясню файл __init__.py на примере ниже:

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

        Если мы добавим функцию в module_n1:

        После работает:

        Затем мы последовали за пакетом иерархии и вызвали функцию module_n1. Мы можем использовать __init__.py в subPackage_b следующим образом:

        После запуска:

        Следовательно, используя * импорт, пакет модуля подчиняется содержимому __init__.py .

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

        Для тех, кто предпочитает читать код, я помещаю здесь комментарий Двухбитового алхимика.

        Читайте также: