Ответы:
Раньше он был обязательной частью пакета ( старый, до 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 (потому что он импортирует ваш пустой файл сейчас). Если вы повторите эти шаги без создания пустого файла инициализации, этого не произойдет. Это то, что он призван предотвратить.
from datetime import datetimeошибку без ошибок. Это хорошо, вплоть до версии 2.3!
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 ).
Названные __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Файл обычно пустой, но может быть использован для экспорта отдельных частей пакета под более удобным названием, трюмные удобные функции и т.д. Учитывая приведенную выше пример, содержимое модуля инициализации можно обращаться как
import spam
основываясь на этом
__init__.pyтребовался в Python 2.X и все еще требуется в Python 2.7.12 (я проверял его), но он больше не требуется (предположительно) начиная с Python 3.3 и далее, и не требуется в Python 3.4.3 (I проверил это). См. Stackoverflow.com/questions/37139786 для получения дополнительной информации.
__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
My __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здесь, я могу начать новый сеанс, используя синтаксис ниже. Этот код будет одинаково выполняться изнутри или снаружи каталога пакета «database».
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... похоже , как ты напутал это пространство имен.
__all__ = [...]для ограничения импорта import *. Но кроме этого, да, у вас осталось грязное пространство имен верхнего уровня.
Есть 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может быть полезным иногда, но не всегда.
__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/
Is __init__. py не требуется для пакетов в Python 3?
В 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
Следовательно, используя * import, модуль пакета зависит от __init__.pyсодержимого.
from package_x.subPackage_b.module_n1 import function_X
Хотя 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
__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
>>>
Это облегчает импорт других файлов Python. Когда вы помещаете этот файл в каталог (скажем, вещи), содержащий другие файлы py, вы можете сделать что-то вроде import stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Без этого __init__.pyвнутри каталога вы не смогли бы импортировать other.py, потому что Python не знает, где находится исходный код материала, и не может распознать его как пакет.
__init__.pyФайл делает импорт легко. Когда __init__.pyв пакете присутствует an , функцию a()можно импортировать из файла b.pyследующим образом:
from b import a
Без этого, однако, вы не можете импортировать напрямую. Вы должны изменить системный путь:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a