Для чего нужен __init__.py? - PullRequest
       139

Для чего нужен __init__.py?

1812 голосов
/ 15 января 2009

Для чего нужно __init__.py в исходном каталоге Python?

Ответы [ 11 ]

1220 голосов
/ 15 января 2009

Раньше это была обязательная часть пакета ( старый, до 3.3 "обычный пакет" , а не более новый 3.3+ "пакет пространства имен" ).

Вот документация.

Python определяет два типа пакетов: обычные пакеты и пакеты пространства имен. Обычные пакеты - это традиционные пакеты, которые существовали в Python 3.2 и более ранних версиях. Обычный пакет обычно реализуется как каталог, содержащий файл __init__.py. Когда обычный пакет импортируется, этот файл __init__.py выполняется неявно, и определяемые им объекты привязываются к именам в пространстве имен пакета. Файл __init__.py может содержать тот же код Python, что и любой другой модуль, и Python добавит некоторые дополнительные атрибуты в модуль при его импорте.

Но просто нажмите на ссылку, она содержит пример, дополнительную информацию и объяснение пакетов пространства имен, типа пакетов без __init__.py.

705 голосов
/ 07 ноября 2010

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

на основе это

417 голосов
/ 24 сентября 2013

В дополнение к маркировке каталога как пакета Python и определению __all__, __init__.py позволяет вам определять любую переменную на уровне пакета. Это часто удобно, если пакет определяет что-то, что будет часто импортироваться в стиле API. Этот паттерн способствует соблюдению философии «квартира лучше вложенного» Pythonic.

Пример

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

143 голосов
/ 08 апреля 2015

Есть 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)
    
96 голосов
/ 15 января 2009

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

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

73 голосов
/ 12 октября 2016

Начиная с 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?

49 голосов
/ 09 января 2014

В 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 содержимого.

38 голосов
/ 12 мая 2018

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

37 голосов
/ 03 января 2015

__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
>>> 
28 голосов
/ 15 января 2009

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

root\
    stuff\
         other.py

    morestuff\
         another.py

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

...