Для чего нужен __init__.py?

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

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

Jun711 16.05.2018 01:13

Пакет без __init__ - это пакет пространства имен, а не обычный пакет. Это не то же самое, как указал @methane с помощью пример здесь.

Catbuilts 24.01.2021 09:50
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2 679
2
1 429 935
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Ответ принят как подходящий

Раньше это была обязательная часть пакета (старый, до 3.3 "обычный пакет", а не более новая версия 3.3+ "пакет пространства имен").

Вот документация.

Python defines two types of packages, regular packages and namespace packages. Regular packages are traditional packages as they existed in Python 3.2 and earlier. A regular package is typically implemented as a directory containing an __init__.py file. When a regular package is imported, this __init__.py file is implicitly executed, and the objects it defines are bound to names in the package’s namespace. The __init__.py file can contain the same Python code that any other module can contain, and Python will add some additional attributes to the module when it is imported.

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

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

Carl G 25.01.2014 08:43

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

Two-Bit Alchemist 08.03.2014 00:56

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

Two-Bit Alchemist 08.03.2014 01:03

@ Two-BitAlchemist При использовании from / import он показывает ImportError: cannot import name 'datetime' в обоих случаях (с __init__.py и без него). пс. Использование Python 3.4 с IDLE.

Darek Nędza 05.05.2014 22:27

@ DarekNędza У вас что-то настроено неправильно, если вы не можете просто открыть интерпретатор Python и запустить from datetime import datetime без ошибок. Это хорошо вплоть до версии 2.3!

Two-Bit Alchemist 06.05.2014 00:10

@ DarekNędza В этом случае ImportError является допустимым результатом, потому что файл datetime.py, который мы помещаем, пуст и не имеет определения для datetime. Импорт был успешным после того, как я поместил в файл класс datetime.

Tapan Chandra 22.08.2014 11:20

@ Two-Bit Alchemist ваша ссылка на документацию и объяснение были полезны, но оставляют вопрос без ответа. Как получается, что у меня может быть каталог только с одним модулем mymodule.py, который содержит определение функции myfunc (), а когда я открываю интерпретатор Python и набираю «import from mymodule myfunc», этого не происходит вывести ошибку. В каталоге отсутствует файл в этом.py, но все же правильно импортировать mymodule.

almel 23.06.2015 00:40

Он всегда смотрит в текущий рабочий каталог процесса оболочки, независимо от того, является ли он модулем. Обычно такие программы работают так, и это не имеет отношения к системе import.

Two-Bit Alchemist 23.06.2015 18:56

Я не знаю, что вы делаете, но смысл пакетов в том, что все модули, такие как html.parser, email.parser и dateutil.parser, имеют уникальные имена, а не все называются просто parser.

Tadhg McDonald-Jensen 03.03.2016 18:02

@ Two-BitAlchemist, я только что заметил документацию о пути поиска модуля (docs.python.org/2/tutorial/modules.html#the-module-search-p‌ ath), там написано, что the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. Если это правда, не должен ли from datetime import datetime всегда импортировать стандартный модуль datetime?

Bin 23.09.2016 22:33

@Bin, datetime не является встроенным модулем, тем более стандартным модулем (docs.python.org/3/tutorial/modules.html#standard-modules). Вы можете просмотреть свои встроенные модули по 'import builtins; dir(builtins)'.

S Wang 24.05.2017 04:11

@SWang: Это неверно: builtins перечисляет встроенные функции и классы, а не встроенные модули (см. docs.python.org/3/tutorial/modules.html#the-dir-function). Если вы хотите вывести список встроенных модули, сделайте import sys; print(sys.builtin_module_names) (см. docs.python.org/3/library/sys.html#sys.builtin_module_names) ‌.

Maggyero 18.01.2018 02:25

@loki, не могли бы вы переместить соответствующие части комментариев к своему сообщению? Следить за кучей комментариев намного сложнее, чем за хорошо отредактированным постом.

styrofoam fly 27.03.2018 19:54

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

Aaron McDaid 28.05.2018 12:32

@AaronMcDaid - почему? что будет, если у вас тоже есть наверху? Благодарю.

danmcb 01.06.2018 12:50

Если мы хотим from a.b.c import f, то есть файл a/b/c.py. Внутри папки __init__.py должен быть a, а также внутри папки a/b. Должен быть нет любой другой __init__.py. Например, если он находится в вашем домашнем каталоге (/home/username/a/b/c.py) и вы создали /home/username/__init__.py, вам понадобится from username.a.b.c import f. По сути, каждый каталог, содержащий __init__.py, должен быть назван в пути импорта.

Aaron McDaid 02.06.2018 19:36

Теперь, поскольку Python3 сделал __init__.py необязательным, я предполагаю, что случайно затенять string или datetime легко, или они представили какой-то другой способ избежать этого?

Konstantin Milyutin 27.10.2018 20:03

@ Two-BitAlchemist, когда вы говорите «это именно то, что предназначено для предотвращения», можете ли вы уточнить это? Я не уверен, что понимаю, что __init__.py предназначен для предотвращения.

Willwsharp 08.04.2019 23:44

@Willwsharp Этот пример касается случайного затенения (здесь хорошее обсуждение слежки). __init__.py просто (в случае, если он пустой) предназначен для того, чтобы явно (см .: «Явное лучше, чем неявное».) сообщить интерпретатору, что это пакет Python, поэтому ему не нужно угадывать.

Two-Bit Alchemist 09.04.2019 19:28

@ Two-BitAlchemist ах, я думаю, теперь понимаю. Формулировка меня смутила. Кроме того, похоже, что встроенные модули Python не могут быть затенены таким образом, как я пытался, и он всегда использовал встроенный datetime вместо моего пакета datetime. Лучшим примером, вероятно, был бы модуль json вместо модуля datetime, поскольку json можно затенять таким образом.

Willwsharp 09.04.2019 22:06

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

root\
    stuff\
         other.py

    morestuff\
         another.py

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

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

rodrigorf 23.10.2018 19:55

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

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

Я думаю, что в этом.py заставляет Python обрабатывать каталоги как пакеты, а не модули. См. docs.python.org/3/tutorial/modules.html

Moses 22.07.2020 10:56

«все пакеты являются модулями, но не все модули являются пакетами» - странно, но факт.

JacKeown 13.10.2020 05:11

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

mydir/spam/__init__.py
mydir/spam/module.py

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

import spam.module

или же

from spam import module

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

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

import spam

на основе это

Обновление: файл __init__.py требовался под Python 2.X и по-прежнему требуется под Python 2.7.12 (я тестировал его), но он больше не требуется от (предположительно) Python 3.3 и новее и не требуется под Python 3.4.3 ( Тестировал). Подробнее см. stackoverflow.com/questions/37139786.

Rob_before_edits 30.10.2016 17:49

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

methane 06.04.2019 04:54

однако, если у вас есть setup.py и вы используете find_packages(), необходимо, чтобы __init__.py был в каждом каталоге. См. stackoverflow.com/a/56277323/7127824

techkuz 23.05.2019 17:40

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

Пример

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

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

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

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

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

from database import Session
session = Session()

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

from database.create_session import Session
session = Session()

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

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

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

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

engine, sessionmaker, create_engine и os теперь могут быть импортированы из database ... похоже, вы испортили это пространство имен.
ArtOfWarfare 23.09.2015 22:28

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

Nathan Gould 24.09.2015 02:28

Могу ли я узнать, что такое URL-адрес БАЗЫ ДАННЫХ? Я попытался воспроизвести это, заключив create_engine в mysql + mysqldb: // root: python @ localhost: 3306 / test, но это не сработало. Спасибо.

SunnyBoiz 25.06.2019 16:34

Как бы вы могли получить доступ к классу Session, определенному в в этом, изнутри пакета, например. quieries.py?

vldbnc 18.09.2019 12:04

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

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

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

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

def function_X():
    print "function_X in module_n1"
    return

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

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

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

__all__ = ['module_n2', 'module_n3']

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

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

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

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

technazi 04.09.2019 23:51

так что ключ здесь - "при использовании * импорта пакет модуля подлежит содержанию в этом.py"

soMuchToLearn 06.03.2020 12:44

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

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

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 

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

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

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    # in file1.py
    def add():
        pass
    

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

    from your_package import add
    

    не зная file1, например

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

    import logging.config
    logging.config.dictConfig(Your_logging_config)
    

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

Aerin 26.02.2018 04:30

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

Tobias Sette 12.12.2019 00:33

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

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

Native support for package directories that don’t require __init__.py marker files and can automatically span multiple path segments (inspired by various third party approaches to namespace packages, as described in PEP 420)

Вот тест:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

ссылки:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
__Init__.py не требуется для пакетов в Python 3?

Это пакет «пространства имён». Не используйте его для обычной упаковки.

methane 06.04.2019 04:55

@methan, не могли бы вы уточнить свой комментарий?

Robert Lugg 04.10.2019 23:41

@RobertLugg См. dev.to/methane/don-t-omit-init-py-3hga

methane 07.10.2019 10:12

Как бы то ни было, этот комментарий решил проблему, отнимавшую 4 часа моего рабочего дня. По какой-то причине сегодня утром Spyder решил, что больше не хочет импортировать мой модуль. Прочитав этот комментарий, я избавился от файла в этом.py, и импорт начал работать. Спасибо @zeekvfu!

autonopy 29.06.2020 19:00

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

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

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

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

main_methods 
    |- methods.py

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

def foo():
    return 'foo'

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

from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()

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


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

import main_methods
print(main_methods.foo()) # Prints 'foo'

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


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

Source code:Lib/json/__init__.py

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

from b import a

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

import sys
sys.path.insert(0, 'path/to/b.py')

from b import a

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

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

def foo():
    ...

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

from util import foo

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

util/
  __init__.py
  util.py
  db.py

и в util / __ init__.py выполните

from util import *

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

from util import foo
from util.db import check_schema

Я думаю, это прекрасно подчеркивает, как __init__.py пакета util действует аналогично модулю util.

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

Разве вы не имеете в виду from util import check_schema, поскольку вы уже сделали в __init __.py from util import *

Mark 16.10.2020 00:31

@Mark нет, from util import * будет в util / __ init__.py, и поэтому не будет импортировать db, а будет импортировать содержимое util / util.py. Уточню ответ

joel 16.10.2020 00:38

Другие вопросы по теме