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

Обновлено: 29.06.2024

Пакет Python — это просто организованный набор модулей Python. Модуль Python — это просто один файл Python.

Зачем мне создавать пакет с помощью __init__.py?

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

Он предоставляет механизм для группировки отдельных скриптов Python в один импортируемый модуль.

Давайте рассмотрим несколько примеров

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

Код в этом руководстве должен работать для Python 2 или 3. Просто помните, что если вы используете 2, вам нужно будет использовать функцию from __future__ import print_function.

Скажем, у нас есть три модуля, которые мы создали:

Помните, что модуль – это просто другое название любого отдельного файла Python

Для нашего примера содержимое этих файлов следующее:

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

Итак, без создания пакета и использования __init__.py как мы можем использовать функции в этих файлах?

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

Ну, мы можем использовать эти файлы в новом скрипте Python, но с одной ключевой оговоркой:

  • Файлы должны находиться в том же каталоге, что и сценарий, в котором мы пытаемся их использовать.

Чтобы проиллюстрировать это, давайте создадим файл с именем example1.py, который использует наши модули:

Добавление пустого файла __init__.py

Что, если бы мы захотели разделить эти скрипты в папку, чтобы они были более организованными?

Именно здесь в игру вступает файл __init__.py.

Во-первых, давайте переместим наши скрипты в новую подпапку и назовем ее: string_func . Затем создайте в этой папке пустой файл с именем __init__.py

Итак, теперь давайте проверим, что именно позволяет нам делать __init__.py:

Давайте создадим новый файл example2.py.

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

Добавление импорта в init.py

Откройте файл __init__.py и внесите следующие изменения:

Итак, теперь в нашем __init__.py мы можем сократить наш код до:

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

Итак, именно это и делает __init__.py! Это позволяет вам обращаться с каталогом, как если бы это был модуль Python. Затем вы можете дополнительно определить импорт в файле __init__.py, чтобы сделать импорт более кратким, или вы можете просто оставить файл пустым.

Отладка проблем с импортом

У меня есть три основных совета по устранению проблем с импортом:

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

Запустите скрипт с помощью команды python -v -m my_scriptname.py, а затем проверьте вывод, чтобы узнать, откуда именно импортируются ваши модули.

Используйте Pycharm. Фантастические возможности самоанализа Pycharm означают, что вы сразу узнаете, правильно ли импортируется ваш модуль, поскольку в противном случае он укажет на ошибку. Иногда он также предлагает правильную коррекцию. Версия для сообщества бесплатна, и если вы студент, вы можете получить бесплатную подписку на ВСЕ их продукты!

Дополнительную информацию о модулях и пакетах Python можно найти в документации по Python.

Вы также можете посмотреть отличный подкаст Talk Python To Me с Дэвидом Бизли, в котором он обсуждает эту тему, а также выступление Дэвида на ту же тему.

Как обычно, не стесняйтесь обращаться ко мне, если обнаружите какие-либо ошибки в этом сообщении!

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

Для этого в Python есть способ поместить определения в файл и использовать их в сценарии или в интерактивном экземпляре интерпретатора.Такой файл называется модулем; определения из модуля можно импортировать в другие модули или в главный модуль (набор переменных, к которым у вас есть доступ в скрипте, выполняемом на верхнем уровне, и в калькуляторе). режим).

Модуль — это файл, содержащий определения и операторы Python. Имя файла — это имя модуля с добавленным суффиксом .py. Внутри модуля имя модуля (в виде строки) доступно как значение глобальной переменной __name__. Например, с помощью вашего любимого текстового редактора создайте файл fibo.py в текущем каталоге со следующим содержимым:

Теперь войдите в интерпретатор Python и импортируйте этот модуль с помощью следующей команды:

Это не вводит имена функций, определенных в fibo, непосредственно в текущую таблицу символов; он вводит туда только имя модуля fibo. Используя имя модуля, вы можете получить доступ к функциям:

Если вы собираетесь часто использовать функцию, вы можете присвоить ей локальное имя:

6.1. Подробнее о модулях¶

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

Каждый модуль имеет свою собственную таблицу символов, которая используется в качестве глобальной таблицы символов всеми функциями, определенными в модуле. Таким образом, автор модуля может использовать глобальные переменные в модуле, не беспокоясь о случайных столкновениях с глобальными переменными пользователя. С другой стороны, если вы знаете, что делаете, вы можете обращаться к глобальным переменным модуля с той же нотацией, которая используется для обозначения его функций, modname.itemname .

Модули могут импортировать другие модули. Обычно, но не обязательно, все операторы импорта помещаются в начало модуля (или скрипта, если уж на то пошло). Имена импортированных модулей помещаются в глобальную таблицу символов импортирующего модуля.

Существует вариант оператора импорта, который импортирует имена из модуля непосредственно в таблицу символов импортирующего модуля. Например:

Это не вводит имя модуля, из которого берутся импорты, в локальную таблицу символов (поэтому в примере фибо не определено).

Существует даже вариант импорта всех имен, определенных модулем:

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

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

Если за именем модуля следует as , то имя после as напрямую связано с импортированным модулем.

Это фактически импортирует модуль так же, как это делает import fibo, с той лишь разницей, что он доступен как fib .

Его также можно использовать при использовании from с аналогичными эффектами:

Из соображений эффективности каждый модуль импортируется только один раз за сеанс интерпретатора. Поэтому, если вы меняете свои модули, вы должны перезапустить интерпретатор — или, если вы хотите протестировать только один модуль в интерактивном режиме, используйте importlib.reload() , например импортировать импортную библиотеку; importlib.reload(имя модуля) .

6.1.1. Выполнение модулей как скриптов¶

Когда вы запускаете модуль Python с

код в модуле будет выполнен так же, как если бы вы его импортировали, но с __name__, установленным на "__main__" . Это означает, что, добавив этот код в конец вашего модуля:

вы можете сделать файл пригодным для использования как скрипт, а также как импортируемый модуль, потому что код, анализирующий командную строку, запускается только в том случае, если модуль выполняется как «основной» файл:

Если модуль импортирован, код не запускается:

Это часто используется либо для предоставления удобного пользовательского интерфейса модулю, либо для целей тестирования (запуск модуля как сценария выполняет набор тестов).

6.1.2. Путь поиска модуля¶

Когда импортируется модуль с именем spam, интерпретатор сначала ищет встроенный модуль с таким именем. Если он не найден, он ищет файл с именем spam.py в списке каталогов, заданном переменной sys.path. sys.path инициализируется из следующих мест:

Каталог, содержащий входной скрипт (или текущий каталог, если файл не указан).

PYTHONPATH (список имен каталогов с тем же синтаксисом, что и переменная оболочки PATH ).

Зависимое от установки значение по умолчанию (по соглашению включает каталог site-packages, обрабатываемый модулем site).

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

После инициализации программы Python могут изменять sys.path . Каталог, содержащий выполняемый скрипт, помещается в начало пути поиска перед стандартным путем библиотеки. Это означает, что скрипты в этом каталоге будут загружены вместо одноименных модулей в каталоге библиотеки. Это ошибка, если замена не предназначена. Дополнительную информацию см. в разделе Стандартные модули.

6.1.3. «Скомпилированные» файлы Python¶

Чтобы ускорить загрузку модулей, Python кэширует скомпилированную версию каждого модуля в каталоге __pycache__ под именем module. версия .pyc , где версия кодирует формат скомпилированного файла; обычно он содержит номер версии Python. Например, в выпуске CPython 3.3 скомпилированная версия spam.py будет кэшироваться как __pycache__/spam.cpython-33.pyc. Это соглашение об именах позволяет сосуществовать скомпилированным модулям из разных выпусков и разных версий Python.

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

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

Несколько советов для экспертов:

Вы можете использовать ключи -O или -OO в команде Python, чтобы уменьшить размер скомпилированного модуля. Переключатель -O удаляет утверждения утверждений, переключатель -OO удаляет как утверждения утверждений, так и строки __doc__. Поскольку некоторые программы могут полагаться на их доступность, вам следует использовать эту опцию только в том случае, если вы знаете, что делаете. «Оптимизированные» модули имеют тег opt-tag и обычно меньше по размеру. В будущих версиях результаты оптимизации могут быть изменены.

При чтении из файла .pyc программа работает не быстрее, чем при чтении из файла .py; единственное, что быстрее в файлах .pyc, — это скорость их загрузки.

Модуль compileall может создавать файлы .pyc для всех модулей в каталоге.

Подробнее об этом процессе, включая блок-схему решений, см. в PEP 3147.

6.2. Стандартные модули¶

Python поставляется с библиотекой стандартных модулей, описанных в отдельном документе — Справочнике по библиотеке Python (далее — «Справочник по библиотеке»). Некоторые модули встроены в интерпретатор; они обеспечивают доступ к операциям, которые не являются частью ядра языка, но, тем не менее, встроены либо для повышения эффективности, либо для предоставления доступа к примитивам операционной системы, таким как системные вызовы. Набор таких модулей является опцией конфигурации, которая также зависит от базовой платформы. Например, модуль winreg предоставляется только в системах Windows. Отдельного внимания заслуживает один конкретный модуль: sys, встроенный в каждый интерпретатор Python. Переменные sys.ps1 и sys.ps2 определяют строки, используемые в качестве основных и дополнительных подсказок:

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

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

6.3. Функция dir()¶

Встроенная функция dir() используется для определения имен, определяемых модулем. Он возвращает отсортированный список строк:

Без аргументов dir() перечисляет имена, которые вы определили в данный момент:

Обратите внимание, что в нем перечислены все типы имен: переменные, модули, функции и т. д.

dir() не перечисляет имена встроенных функций и переменных. Если вам нужен их список, они определены в стандартных встроенных модулях:

6.4. Пакеты¶

Пакеты — это способ структурирования пространства имен модулей Python с помощью «точечных имен модулей». Например, имя модуля A.B обозначает подмодуль с именем B в пакете с именем A. Точно так же, как использование модулей избавляет авторов разных модулей от необходимости беспокоиться об именах глобальных переменных друг друга, использование имен модулей с точками избавляет авторов многомодульных пакетов, таких как NumPy или Pillow, от необходимости беспокоиться об именах модулей друг друга. .

Предположим, вы хотите разработать набор модулей («пакет») для единообразной обработки звуковых файлов и звуковых данных.Существует множество различных форматов звуковых файлов (обычно распознаваемых по их расширениям, например: .wav, .aiff, .au), поэтому вам может потребоваться создать и поддерживать растущую коллекцию модулей для преобразования между различными форматами файлов. Существует также множество различных операций, которые вы, возможно, захотите выполнить со звуковыми данными (например, микширование, добавление эха, применение функции эквалайзера, создание искусственного стереоэффекта), так что, кроме того, вы будете писать нескончаемый поток модулей для выполнения. эти операции. Вот возможная структура вашего пакета (выраженная в терминах иерархической файловой системы):

При импорте пакета Python просматривает каталоги sys.path в поисках подкаталога пакета.

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

Пользователи пакета могут импортировать отдельные модули из пакета, например:

Это загружает подмодуль sound.effects.echo. На него должно указываться его полное имя.

Альтернативный способ импорта подмодуля:

Это также загружает подмодуль echo и делает его доступным без префикса пакета, поэтому его можно использовать следующим образом:

Еще один вариант — импортировать нужную функцию или переменную напрямую:

Опять же, это загружает подмодуль echo , но делает его функцию echofilter() доступной напрямую:

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

Наоборот, при использовании синтаксиса наподобие import item.subitem.subsubitem каждый элемент, кроме последнего, должен быть пакетом; последний элемент может быть модулем или пакетом, но не может быть классом, функцией или переменной, определенной в предыдущем элементе.

6.4.1. Импорт * из пакета¶

Что происходит, когда пользователь пишет из sound.effects import * ? В идеале можно было бы надеяться, что это каким-то образом выйдет в файловую систему, найдет, какие подмодули присутствуют в пакете, и импортирует их все. Это может занять много времени, а импорт подмодулей может привести к нежелательным побочным эффектам, которые должны иметь место только при явном импорте подмодуля.

Единственным решением для автора пакета является предоставление явного индекса пакета. В операторе импорта используется следующее соглашение: если код пакета __init__.py определяет список с именем __all__ , он считается списком имен модулей, которые следует импортировать, когда встречается from package import *. Автор пакета должен поддерживать этот список в актуальном состоянии при выпуске новой версии пакета. Авторы пакетов также могут принять решение не поддерживать его, если они не видят смысла в импорте * из своего пакета. Например, файл sound/effects/__init__.py может содержать следующий код:

Это будет означать, что из sound.effects import * будут импортированы три именованных подмодуля звукового пакета.

Если __all__ не определено, инструкция из sound.effects import * не импортирует все подмодули из пакета sound.effects в текущее пространство имен; это только гарантирует, что пакет sound.effects был импортирован (возможно, запуск любого кода инициализации в __init__.py ), а затем импортирует любые имена, определенные в пакете. Сюда входят любые имена, определенные (и явно загруженные подмодули) с помощью __init__.py. Он также включает любые подмодули пакета, которые были явно загружены предыдущими операторами импорта. Рассмотрим этот код:

В этом примере модули эха и объемного звучания импортируются в текущее пространство имен, поскольку они определены в пакете sound.effects, когда файл from. выполняется оператор импорта. (Это также работает, когда определено __all__.)

Несмотря на то, что некоторые модули предназначены для экспорта только тех имен, которые соответствуют определенным шаблонам при использовании import * , это по-прежнему считается плохой практикой в ​​производственном коде.

Помните, что нет ничего плохого в использовании from package importspecific_submodule ! На самом деле это рекомендуемая нотация, если импортирующему модулю не нужно использовать подмодули с одинаковыми именами из разных пакетов.

6.4.2. Внутрипакетные ссылки¶

Когда пакеты структурированы в подпакеты (как в случае со звуковым пакетом в примере), вы можете использовать абсолютный импорт для ссылки на подмодули одноуровневых пакетов. Например, если модуль sound.filters.вокодер должен использовать модуль echo в пакете sound.effects, он может использовать from sound.effects import echo .

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

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

6.4.3. Пакеты в нескольких каталогах¶

Пакеты поддерживают еще один специальный атрибут — __path__ . Он инициализируется как список, содержащий имя каталога, содержащего __init__.py пакета, до выполнения кода в этом файле. Эту переменную можно изменить; это повлияет на дальнейший поиск модулей и подпакетов, содержащихся в пакете.

Хотя эта функция требуется нечасто, ее можно использовать для расширения набора модулей в пакете.

Фактически определения функций также являются «операторами», которые «выполняются»; выполнение определения функции на уровне модуля вводит имя функции в глобальную таблицу символов модуля.

Для чего нужен файл __init__.py в исходном каталоге Python?

Согласно приведенному ниже комментарию @Rob_before_edits и этой ветке stackoverflow 37139786, кажется, что init.py больше не нужен для Python 3.3+.

Пакет без __init__ является пакетом пространства имен, а не обычным пакетом. Это не то же самое, что @mthan указал здесь в качестве примера.

@Rainning Пакет пространства имен принципиально не отличается от обычного пакета. Это просто другой способ создания пакетов. После создания пакета пространства имен между ним и обычным пакетом не будет функциональной разницы.

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

12 ответов 12

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

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

Что это значит: "это делается для того, чтобы каталоги с общим именем, например string, непреднамеренно скрывали допустимые модули, которые встречаются позже на пути поиска модулей"?

@CarlG Python ищет список каталогов для разрешения имен, например, в операторах импорта. Поскольку это может быть любой каталог, а конечный пользователь может добавить произвольные каталоги, разработчикам приходится беспокоиться о каталогах, имена которых совпадают с действительным модулем Python, например, «string» в примере с документацией. Чтобы облегчить это, он игнорирует каталоги, которые не содержат файл с именем _ _ init _ _.py (без пробелов), даже если он пуст.

@CarlG Попробуйте это. Создайте каталог с именем «datetime» и создайте в нем два пустых файла: файл init.py (с символами подчеркивания) и datetime.py. Теперь откройте интерпретатор, импортируйте sys и введите sys.path.insert(0, '/path/to/datetime') , заменив этот путь на путь к любому каталогу, который вы только что создали. Теперь попробуйте что-то вроде from datetime import datetime;datetime.now() . Вы должны получить AttributeError (потому что сейчас он импортирует ваш пустой файл). Если бы вы повторили эти шаги без создания пустого файла инициализации, этого бы не произошло. Это то, что он предназначен для предотвращения.

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

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

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

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

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

Пример

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

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

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

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

Дополнительная литература

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

engine, sessionmaker, create_engine и os теперь также можно импортировать из базы данных. похоже, вы испортили это пространство имен.

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

@NathanGould, вы также можете использовать переменные подчеркивания с одним ведущим, которые по умолчанию не импортируются с помощью import *. Например: импортируйте os как _os и используйте _os внутри модуля __init__.py вместо os .

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

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

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

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

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

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

@Aerin, лучше не считать короткие утверждения (или, в данном случае, субъективные выводы) всегда верными. Импорт из __init__.py иногда может быть полезен, но не всегда.

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

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

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

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

< /цитата>

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

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

Есть также случай, когда вы действительно можете использовать файл __init__.py:

И в method.py было следующее:

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

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

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

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

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

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

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

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

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

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

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

Как мой setup.py будет выглядеть, чтобы выполнить тот же импорт через упакованную библиотеку? из package_x.subPackage_b.module_n1 импортировать function_X

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

Для тех, кто предпочитает читать код, я помещаю здесь комментарий Two-Bit Alchemist.

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

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

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

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

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

Одна вещь, которую позволяет __init__.py, — это преобразование модуля в пакет без нарушения API или создания посторонних вложенных пространств имен или частных модулей*. Это помогает, когда я хочу расширить пространство имен.

Если у меня есть файл util.py, содержащий

тогда пользователи будут получать доступ к foo с помощью

Если я затем захочу добавить служебные функции для взаимодействия с базой данных, и я хочу, чтобы у них было собственное пространство имен в util , мне понадобится новый каталог** и сохранить совместимость API (чтобы из util import foo по-прежнему работает), я назову его util/. Я мог переместить util.py в util/ вот так,

и в util/__init__.py сделать

но это лишнее. Вместо файла util/util.py мы можем просто поместить содержимое util.py в __init__.py, и теперь пользователь сможет

Я думаю, что это хорошо показывает, как __init__.py служебного пакета действует аналогично служебному модулю

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

Просматривая примеры проектов Python, вы, возможно, видели этот файл, __init__.py. Возможно, вам было интересно, что это такое, зачем оно там, если оно пусто, и как оно работает. Этот пост ответит на все эти вопросы!

Вот пример структуры файла, который включает __init__.py:

Главная папка — это наш каталог Python, который мы хотим рассматривать как пакет Python. Чтобы считаться таковым, мы должны включить файл __init__.py, который передает эту информацию интерпретатору Python.

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

В main.py мы будем вызывать функции, сохраненные в main_package. Через минуту вы увидите, как это работает, но сначала давайте взглянем на файл __init__.py.

Что такое __init__.py?

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

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

81 % участников заявили, что стали более уверенными в своих перспективах работы в сфере технологий после посещения учебного курса. Примите участие в тренировочном лагере сегодня.

Найдите подходящий вариант для буткемпа

В среднем выпускник буткемпа тратит менее шести месяцев на смену карьеры, начиная с буткемпа и заканчивая поиском своей первой работы.

Начните сменить профессию сегодня

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

1. main_package/__init__.py и явный импорт:

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

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

Это говорит нам, какие именно модули мы используем вне main_package.

2. main_package/__init__.py и стандартный импорт:

Единственная разница между этим и предыдущим заключается в том, что первый импортирует только то, что нам нужно (файл_1, файл_2, файл_3). Другой импортирует модуль, поэтому мы используем запись через точку для доступа к именам функций.

3. main_package/__init__.py и импорт подстановочных знаков:

В __init__.py задайте для переменной __all__ список модулей/файлов в пакете. Это поможет интерпретатору понять, что следует учитывать, когда мы используем оператор импорта подстановочных знаков в main.py. Обратите внимание, что переменная all окружена двумя символами подчеркивания с обеих сторон.

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

Поиск в Google приводит к stackoverflow, который ссылается на документацию по Python. Суть в том, что __init__.py используется для указания того, что каталог является пакетом Python. (Небольшое примечание о пакетах и ​​модулях из документации по python: «С точки зрения файловой системы пакеты — это каталоги, а модули — это файлы».) Если мы хотим, чтобы папка считалась пакетом Python, нам нужно включить файл __init__.py. Но что мы должны в него поместить?

Существует ряд вариантов того, что можно поместить в файл __init__.py. Самое минимальное, что нужно сделать, это оставить файл __init__.py полностью пустым. Немного отойдя от этого, но сохраняя простоту, вы можете использовать __init__.py только для определения порядка импорта. Еще один шаг вперед — вы можете использовать файл __init__.py для определения API пакета. И последний шаг — вы можете просто определить весь пакет в __init__.py .

Я рассмотрю плюсы и минусы каждого из этих 4 подходов и приведу их примеры в оставшейся части поста.

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

И мы хотим импортировать модуль "a", оператор foo import a просматривает каталог foo, видит __init__.py . Он знает, что foo следует рассматривать как пакет, и выполняет его __init__.py, а затем ищет, как импортировать файл . (Вы можете проверить это поведение, воссоздав эту структуру каталогов и поместив операторы печати в файлы. Если вы сделаете это из foo import c , вы получите ImportError , но не после выполнения оператора печати в foo/__init__.py. Если вы заинтересованы в копании исходного кода python, код для importlib доступен на github, а спецификация для общего протокола импортера находится в PEP-302). Оставив наш файл __init__.py пустым, мы упустим возможность использовать это.

Еще один недостаток связан с пространствами имен. В структуре каталогов, указанной выше, импортировать foo куда угодно будет бесполезно. Чтобы получить доступ к любому нашему фактическому коду, мы должны импортировать подмодули. В дополнение к тому, что операторы импорта становятся длиннее, сложно давать имена. К сожалению, придумать отличное имя для пакета или подпакета, а затем также нужно придумать хорошие имена для подмодулей, поскольку это то, на что вы в конечном итоге будете ссылаться.

Пример использования этого подхода в исходном коде Python находится в urllib.

Затем, когда мы запускаем import foo.b , гарантируется, что a.py будет выполнен до b.py . (Этот пример зависимости немного надуманный; я не имею в виду, что подмодули должны иметь привычку записывать файлы при импорте.)

Примером использования такого подхода является пакет fsq, описанный в сообщении, которое я упоминал выше.

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

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

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

Пример такого подхода в коде библиотеки Python находится в модуле json. Файл __init__.py предоставляет функции дампа, дампа и загрузки, которые зависят от функций, определенных в подмодулях.

Последний вариант — поместить весь пакет в файл __init__.py. Это может хорошо работать для небольших пакетов. Это избавляет от необходимости придумывать кучу новых имен.

Однако по мере увеличения размера пакета один файл может стать громоздким.

Примером такого подхода является модуль коллекций. (Хотя технически у него есть один подмодуль.)

Подпишитесь, чтобы узнать больше.

Rust: Что выбрать для типа ошибки при написании собственного типа результата

Rust: что выбрать для типа ошибки при написании собственного типа результата

Тип результата в rust великолепен! В сочетании с ? оператор, он делает обработку ошибок намного более лаконичной, чем другие языки. Рассмотреть возможность ? vs: Иди: если ошибся!= nil < возвращает nil, ошибка > Java: try < . >ловить < . >& throwsПри определении моего собственного типа Result оставить общий тип T действительно

Observable + bean-count

Наблюдаемый + подсчет бобов

В последнее время мне больше всего нравятся два инструмента: Observable (observablehq.com) (давно пользующийся популярностью для быстрого прототипирования JavaScript и создания интерактивных визуализаций) и bean-count (недавнее дополнение для ведения "любительского учета с двойной записью" (специальный форма «веселье»)). fava — отличный веб-интерфейс с открытым исходным кодом для подсчета компонентов, который

Изучение изменчивости в Rust

Я впервые за долгое время пишу Rust и столкнулся с проблемой изменчивости, которую решил написать. То, что я пытался сделать, это создать клиент, который создает тело ответа XML, а затем отправляет запрос на сервер. Есть

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