Для чего нужен __init__.py ?
-
19-08-2019 - |
Вопрос
Что такое __init__.py
для в исходном каталоге Python?
Решение
Раньше он был обязательной частью пакета ( старый, предварительно -3.3 & Quot; обычный пакет & Quot; , а не более новый 3.3+ " пакет пространства имен " ).
Python определяет два типа пакетов: обычные пакеты и пакеты пространства имен. Обычные пакеты - это традиционные пакеты, которые существовали в Python 3.2 и более ранних версиях. Обычный пакет обычно реализуется как каталог, содержащий файл
__init__.py
. Когда обычный пакет импортируется, этот файл <=> выполняется неявно, и определяемые им объекты привязываются к именам в пространстве имен пакета & # 8217; s. Файл <=> может содержать тот же код Python, что и любой другой модуль, и Python добавит некоторые дополнительные атрибуты в модуль при его импорте.
Но просто нажмите на ссылку, она содержит пример, дополнительную информацию и объяснение пакетов пространства имен, типа пакетов без <=>.
Другие советы
Файлы с именем __init__.py
используются для пометки каталогов на диске как каталогов пакетов Python.
Если у вас есть файлы
mydir/spam/__init__.py
mydir/spam/module.py
и mydir
на вашем пути, вы можете импортировать код в module.py
как
import spam.module
или
from spam import module
Если вы удалите файл <=>, Python больше не будет искать подмодули внутри этого каталога, поэтому попытки импорта модуля завершатся неудачей.
Файл <=> обычно пуст, но его можно использовать для экспорта выбранных частей пакета под более удобным именем, хранения вспомогательных функций и т. д. Учитывая приведенный выше пример, доступ к содержимому модуля init можно получить как
import spam
на основе этой
В дополнение к маркировке каталога как пакета Python и определению __all__
__init__.py
позволяет определить любую переменную на уровне пакета. Это часто удобно, если пакет что-то определяет это будет импортироваться часто, в стиле API. Этот шаблон способствует соблюдению Pythonic &; Квартира лучше, чем вложенная & Quot; философии. р>
Пример
Вот пример из одного из моих проектов, в котором я часто импортирую sessionmaker
с именем Session
для взаимодействия с моей базой данных. Я написал & Quot; database & Quot; пакет с несколькими модулями:
database/
__init__.py
schema.py
insertions.py
queries.py
My <=> содержит следующий код:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Поскольку я определяю здесь <=>, я могу начать новый сеанс, используя приведенный ниже синтаксис. Этот код будет выполнен одинаково внутри или снаружи & Quot; database & Quot; каталог пакетов.
from database import Session
session = Session()
Конечно, это небольшое удобство - альтернативой может быть определение <=> в новом файле, например " create_session.py " в моем пакете базы данных и начинайте новые сеансы, используя:
from database.create_session import Session
session = Session()
Дальнейшее чтение
Здесь есть довольно интересная ветка reddit, в которой рассказывается о соответствующих случаях использования <=>:
http://www.reddit.com/r/Python/comments/1bbbwk/whin____inin_y_ р>
По мнению большинства, <=> файлы должны быть очень тонкими, чтобы не нарушать &; явное лучше, чем неявное " философии. р>
Существует две основные причины __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
заставляет Python обращаться с каталогами, содержащими его, как с модулями. Р>
Кроме того, это первый файл, который загружается в модуль, поэтому вы можете использовать его для выполнения кода, который вы хотите запускать каждый раз при загрузке модуля, или указывать субмодули для экспорта.
Начиная с Python 3.3, __init__.py
больше не требуется определять каталоги как импортируемые пакеты Python.
Проверить БОДРОСТЬ ДУХА 420:Неявные пакеты пространства имен:
Встроенная поддержка каталогов пакетов, которые не требуют
__init__.py
маркерные файлы и могут автоматически охватывать несколько сегментов пути (вдохновленные различными сторонними подходами к пакетам пространств имен, как описано в БОДРОСТЬ ДУХА 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 определение пакета очень просто. Как и в Java, иерархическая структура и структура каталогов одинаковы. Но вы должны иметь __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
<=> может быть пустым, если он существует. Это указывает на то, что каталог следует рассматривать как пакет. Конечно, <=> также может установить соответствующий контент.
Если мы добавим функцию в 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 функцию. Мы можем использовать <=> в 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, пакет модуля зависит от содержания <=>.
Несмотря на то, что Python работает без файла __init__.py
, вы все равно должны включить его.
Он указывает, что пакет должен рассматриваться как модуль, поэтому включите его (даже если он пуст).
В некоторых случаях вы можете использовать methods.py
файл:
Представьте, что у вас была следующая файловая структура:
main_methods
|- methods.py
И foo()
содержал это:
def foo():
return 'foo'
Для использования main_methods
вам понадобится одно из следующих действий:
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()
Возможно, вам нужно (или вы хотите) сохранить import json
внутри json
(например, среды выполнения / зависимости), но вы хотите импортировать только Lib/json/__init__.py
.
Если вы изменили имя <=> на <=>, вы можете использовать <=>, просто импортировав <=>:
import main_methods
print(main_methods.foo()) # Prints 'foo'
Это работает, потому что <=> рассматривается как часть пакета.
<Ч>Некоторые пакеты Python действительно делают это. Примером может служить JSON , где при запуске <=> фактически импортируется <=> из пакета <=> ( см. здесь структуру файла пакета ): р>
Исходный код: <=>
__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
упрощает импорт. Когда в пакете присутствует a()
, функцию b.py
можно импортировать из файла <=> следующим образом:
from b import a
Без этого вы не можете импортировать напрямую. Вы должны изменить системный путь:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a