Что означает __init__.py
в исходном каталоге Python?
Для чего нужен __init__.py?
Ответы (12)
Раньше он был обязательной частью пакета (старый, до 3.3 " обычный пакет ", а не новее 3.3+" пакет пространства имен "< / а>).
Python определяет два типа пакетов: обычные пакеты и пакеты пространства имен. Обычные пакеты - это традиционные пакеты, существовавшие в Python 3.2 и ранее. Обычный пакет обычно реализуется как каталог, содержащий файл
__init__.py
. Когда импортируется обычный пакет, этот__init__.py
файл неявно выполняется, а объекты, которые он определяет, привязываются к именам в пространстве имен пакета. Файл__init__.py
может содержать тот же код Python, что и любой другой модуль, и Python добавит в модуль некоторые дополнительные атрибуты при его импорте.
Но просто щелкните ссылку, она содержит пример, дополнительную информацию и объяснение пакетов пространства имен, то есть пакетов без __init__.py
.
sys.path.insert(0, '/path/to/datetime')
, заменив этот путь на путь к любому каталогу, который вы только что создали. Теперь попробуйте что-нибудь вроде from datetime import datetime;datetime.now()
. Вы должны получить AttributeError (потому что сейчас он импортирует ваш пустой файл). Если бы вы повторили эти шаги, не создав пустой файл инициализации, этого бы не произошло. Это то, что он предназначен для предотвращения.
- person Two-Bit Alchemist; 08.03.2014
Файлы с именами __init__.py
используются для пометки каталогов на диске как каталогов пакетов Python. Если у вас есть файлы
mydir/spam/__init__.py
mydir/spam/module.py
и mydir
находится на вашем пути, вы можете импортировать код в module.py
как
import spam.module
or
from spam import module
Если вы удалите файл __init__.py
, Python больше не будет искать подмодули внутри этого каталога, поэтому попытки импортировать модуль не удастся.
Файл __init__.py
обычно пуст, но может использоваться для экспорта выбранных частей пакета под более удобным именем, хранения вспомогательных функций и т. Д. В приведенном выше примере доступ к содержимому модуля инициализации можно получить как
import spam
на основе это
__init__.py
требовался под Python 2.X и по-прежнему требуется под Python 2.7.12 (я тестировал его), но он больше не требуется от (предположительно) Python 3.3 и далее и не требуется под Python 3.4.3 ( Тестировал). Подробнее см. stackoverflow.com/questions/37139786.
- person Rob_before_edits; 30.10.2016
Помимо обозначения каталога как пакета 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
:
Большинство считает, что __init__.py
файлы должны быть очень тонкими, чтобы не нарушать философию «явное лучше, чем неявное».
engine
, sessionmaker
, create_engine
и os
теперь могут быть импортированы из database
... похоже, вы испортили это пространство имен.
- person ArtOfWarfare; 23.09.2015
__all__ = [...]
, чтобы ограничить то, что импортируется с import *
. Но помимо этого, да, у вас остается запутанное пространство имен верхнего уровня.
- person Nathan Gould; 24.09.2015
import *
по умолчанию. Например: import os as _os
и используйте _os
внутри модуля __init__.py
вместо os
.
- person Mathieu Rollet; 23.07.2021
Есть 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)
__init__.py
может быть полезен иногда, но не всегда.
- person Tobias Sette; 12.12.2019
Файл __init__.py
заставляет Python рассматривать содержащие его каталоги как модули.
Кроме того, это первый файл, загружаемый в модуль, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз при загрузке модуля, или указать подмодули для экспорта.
Начиная с Python 3.3, __init__.py
больше не требуется для определения каталогов как импортируемых пакетов Python.
Проверьте PEP 420: неявные пакеты пространства имен :
Встроенная поддержка каталогов пакетов, которые не требуют
__init__.py
файлов маркеров и могут автоматически охватывать несколько сегментов пути (на основе различных сторонних подходов к пакетам пространств имен, как описано в 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?
Хотя 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
(см. структуру файла пакета здесь):
Исходный код:
Lib/json/__init__.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
содержимого.
from package_x.subPackage_b.module_n1 import function_X
- person technazi; 04.09.2019
__init__.py
будет рассматривать каталог, в котором он находится, как загружаемый модуль.
Для людей, которые предпочитают читать код, я помещаю здесь комментарий Two-Bit Alchemist.
$ 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
>>>
Это облегчает импорт других файлов Python. Когда вы поместили этот файл в каталог (скажем, stuff), содержащий другие файлы py, вы можете сделать что-то вроде import stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Без этого __init__.py
внутри каталога вы не смогли бы импортировать other.py, потому что Python не знает, где находится исходный код для материала, и не может распознать его как пакет.
Файл __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 *
- person Mark; 16.10.2020
from util import *
будет в util / __ init__.py, поэтому не будет импортировать db
, а будет импортировать содержимое util / util.py. Уточню ответ
- person joel; 16.10.2020
__init__
- это пакет пространства имен, а не обычный пакет. Это не то же самое, на что указывает @methane с помощью пример здесь. - person Catbuilts   schedule 24.01.2021