Что такое init.py за что?



Что такое __init__.py для исходного каталога Python?

813   11  

11 ответов:

Это часть пакета. вот документация.

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

Файлы с именем __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

На основе этого

В дополнение к маркировке каталога как пакета 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 здесь, я могу начать новый сеанс, используя синтаксис ниже. Этот код будет таким же, выполняемым изнутри или снаружи каталога пакета "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/

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

Есть 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)
    

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

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

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

Check 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

References:
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 в пакете. Я объясню файл __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.

__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
>>> 

Что такое __init__.py используется для чего?

В __init__.py для инициализации пакетов Python. Самый простой способ продемонстрировать это-взглянуть на структуру стандартного модуля Python.

package/
    __init__.py
    file.py
    file2.py
    file3.py
    subpackage/
        __init__.py
        submodule1.py
        submodule2.py
Как вы можете видеть в приведенной выше структуре, включение файла __init__.py в каталог указывает интерпретатору Python, что каталог должен рассматриваться как пакет Python

Что входит в __init__.py?

__init__.py может быть Ан пустой файл, но он часто используется для выполнения установки, необходимой для пакета (импорт вещей, загрузка вещей в путь и т. д.).

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

В приведенном выше примере мы можем сказать, что file.py имеет файл класса. Поэтому без чего-либо в нашем __init__.py вы импортировали бы с помощью этого синтаксиса:

from package.file import File

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

# in your __init__.py
from file import File

# now import File from package
from package import File

Еще одна вещь, которую нужно сделать, - это на уровне пакета сделать доступными подпакеты/модули с переменной __all__. Когда интерпетер видит переменную __all__, определенную в переменной __init__.py, он импортирует модули, перечисленные в переменной __all__, Когда вы делаете:

from package import *

__all__ это список, содержащий имена модулей, которые вы хотите импортировать с помощью import * так что посмотрите на наш приведенный выше пример еще раз, если мы хотим импортировать подмодули в подпакет переменная __all__ в subpackage/__init__.py будет иметь вид:

__all__ = ['submodule1', 'submodule2']

С переменной __all__, заполненной таким образом, когда вы выполняете

from subpackage import *

Он будет импортировать submodule1 и submodule2.

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

Ссылка

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

root\
    stuff\
         other.py

    morestuff\
         another.py

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

Хотя 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

Comments

    Ничего не найдено.