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






Раньше это была обязательная часть пакета (старый, до 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__.pyfile. When a regular package is imported, this__init__.pyfile is implicitly executed, and the objects it defines are bound to names in the package’s namespace. The__init__.pyfile 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.
Что это означает: «это сделано для того, чтобы каталоги с общим именем, таким как строка, не могли непреднамеренно скрыть действительные модули, которые встречаются позже на пути поиска модулей»?
@CarlG Python ищет список каталогов для разрешения имен, например, в операторах импорта. Поскольку это может быть любой каталог, а конечный пользователь может добавлять произвольные, разработчикам приходится беспокоиться о каталогах, которые имеют общее имя с допустимым модулем Python, например, «строка» в примере с документами. Чтобы облегчить это, он игнорирует каталоги, которые не содержат файл с именем _ _ init _ _.py (без пробелов), даже если он пуст.
@CarlG Попробуй. Создайте каталог с именем datetime и создайте в нем два пустых файла: файл init.py (с подчеркиванием) и datetime.py. Теперь откройте интерпретатор, импортируйте sys и запустите sys.path.insert(0, '/path/to/datetime'), заменив этот путь на путь к любому каталогу, который вы только что создали. Теперь попробуйте что-нибудь вроде from datetime import datetime;datetime.now(). Вы должны получить AttributeError (потому что сейчас он импортирует ваш пустой файл). Если бы вы повторили эти шаги, не создав пустой файл инициализации, этого бы не произошло. Это то, что он предназначен для предотвращения.
@ Two-BitAlchemist При использовании from / import он показывает ImportError: cannot import name 'datetime' в обоих случаях (с __init__.py и без него). пс. Использование Python 3.4 с IDLE.
@ DarekNędza У вас что-то настроено неправильно, если вы не можете просто открыть интерпретатор Python и запустить from datetime import datetime без ошибок. Это хорошо вплоть до версии 2.3!
@ DarekNędza В этом случае ImportError является допустимым результатом, потому что файл datetime.py, который мы помещаем, пуст и не имеет определения для datetime. Импорт был успешным после того, как я поместил в файл класс datetime.
@ Two-Bit Alchemist ваша ссылка на документацию и объяснение были полезны, но оставляют вопрос без ответа. Как получается, что у меня может быть каталог только с одним модулем mymodule.py, который содержит определение функции myfunc (), а когда я открываю интерпретатор Python и набираю «import from mymodule myfunc», этого не происходит вывести ошибку. В каталоге отсутствует файл в этом.py, но все же правильно импортировать mymodule.
Он всегда смотрит в текущий рабочий каталог процесса оболочки, независимо от того, является ли он модулем. Обычно такие программы работают так, и это не имеет отношения к системе import.
Я не знаю, что вы делаете, но смысл пакетов в том, что все модули, такие как html.parser, email.parser и dateutil.parser, имеют уникальные имена, а не все называются просто parser.
@ 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, datetime не является встроенным модулем, тем более стандартным модулем (docs.python.org/3/tutorial/modules.html#standard-modules). Вы можете просмотреть свои встроенные модули по 'import builtins; dir(builtins)'.
@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) .
@loki, не могли бы вы переместить соответствующие части комментариев к своему сообщению? Следить за кучей комментариев намного сложнее, чем за хорошо отредактированным постом.
Можем ли мы просто сказать, что в каждом каталоге Кроме верхнего уровня должен быть файл __init.py__? Мне потребовалось много экспериментов, чтобы понять, что нужно удалить верхний уровень!
@AaronMcDaid - почему? что будет, если у вас тоже есть наверху? Благодарю.
Если мы хотим 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, должен быть назван в пути импорта.
Теперь, поскольку Python3 сделал __init__.py необязательным, я предполагаю, что случайно затенять string или datetime легко, или они представили какой-то другой способ избежать этого?
@ Two-BitAlchemist, когда вы говорите «это именно то, что предназначено для предотвращения», можете ли вы уточнить это? Я не уверен, что понимаю, что __init__.py предназначен для предотвращения.
@Willwsharp Этот пример касается случайного затенения (здесь хорошее обсуждение слежки). __init__.py просто (в случае, если он пустой) предназначен для того, чтобы явно (см .: «Явное лучше, чем неявное».) сообщить интерпретатору, что это пакет Python, поэтому ему не нужно угадывать.
@ Two-BitAlchemist ах, я думаю, теперь понимаю. Формулировка меня смутила. Кроме того, похоже, что встроенные модули Python не могут быть затенены таким образом, как я пытался, и он всегда использовал встроенный datetime вместо моего пакета datetime. Лучшим примером, вероятно, был бы модуль json вместо модуля datetime, поскольку json можно затенять таким образом.
Это облегчает импорт других файлов 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, но не в командной строке. Любые идеи?
Файл __init__.py заставляет Python рассматривать каталоги, содержащие его, как модули.
Кроме того, это первый файл, загружаемый в модуль, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз при загрузке модуля, или указать подмодули для экспорта.
Я думаю, что в этом.py заставляет Python обрабатывать каталоги как пакеты, а не модули. См. docs.python.org/3/tutorial/modules.html
«все пакеты являются модулями, но не все модули являются пакетами» - странно, но факт.
Файлы с именем __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.
Не используйте это. Это пакет «пространства имен», а не обычный пакет. пакет namespace используется в очень редких случаях. Возможно, вам не нужно знать, когда его использовать. Просто используйте __init__.py.
однако, если у вас есть setup.py и вы используете find_packages(), необходимо, чтобы __init__.py был в каждом каталоге. См. stackoverflow.com/a/56277323/7127824
Помимо обозначения каталога как пакета 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, вы можете использовать __all__ = [...], чтобы ограничить то, что импортируется с import *. Но помимо этого, да, у вас остается запутанное пространство имен верхнего уровня.
Могу ли я узнать, что такое URL-адрес БАЗЫ ДАННЫХ? Я попытался воспроизвести это, заключив create_engine в mysql + mysqldb: // root: python @ localhost: 3306 / test, но это не сработало. Спасибо.
Как бы вы могли получить доступ к классу Session, определенному в в этом, изнутри пакета, например. quieries.py?
В 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
так что ключ здесь - "при использовании * импорта пакет модуля подлежит содержанию в этом.py"
__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.
Для удобства: другим пользователям не нужно знать точное расположение ваших функций в иерархии пакетов.
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
Если вы хотите, чтобы что-то было инициализировано; например, логирование (которое нужно поставить на верхний уровень):
import logging.config
logging.config.dictConfig(Your_logging_config)
о, прежде чем прочитать ваш ответ, я подумал, что вызов функции явно из ее местоположения - это хорошая практика.
@Aerin было бы лучше не считать короткие утверждения (или, в данном случае, субъективные выводы) верными. Импорт из __init__.py может быть полезен иногда, но не всегда.
Начиная с Python 3.3, __init__.py больше не требуется для определения каталогов как импортируемых пакетов Python.
Проверьте PEP 420: неявные пакеты пространства имен:
Native support for package directories that don’t require
__init__.pymarker 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?
Это пакет «пространства имён». Не используйте его для обычной упаковки.
@methan, не могли бы вы уточнить свой комментарий?
@RobertLugg См. dev.to/methane/don-t-omit-init-py-3hga
Как бы то ни было, этот комментарий решил проблему, отнимавшую 4 часа моего рабочего дня. По какой-то причине сегодня утром Spyder решил, что больше не хочет импортировать мой модуль. Прочитав этот комментарий, я избавился от файла в этом.py, и импорт начал работать. Спасибо @zeekvfu!
Хотя 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 нет, from util import * будет в util / __ init__.py, и поэтому не будет импортировать db, а будет импортировать содержимое util / util.py. Уточню ответ
Согласно приведенному ниже комментарию @Rob_before_edits и этот поток stackoverflow 37139786, похоже, что в этом.py больше не нужен для Python 3.3+.