Добавление кода в init.py


Я смотрю на то, как работает модельная система в django, и я заметил кое-что, что я не понимаю.

Я знаю, что вы создаете пустой __init__.py файл, чтобы указать, что текущий каталог является пакетом. И что вы можете установить некоторую переменную в __init__.py Так что импорт * работает правильно.

но Джанго добавляет кучу от ... импорт... операторы и определяет кучу классов в __init__.py. Зачем? Разве это не заставляет вещи выглядеть грязными? Есть причина, которая требует этот код в __init__.py?

3 77

3 ответа:

все импорт в __init__.py становятся доступными при импорте пакета (каталога), который его содержит.

пример:

./dir/__init__.py:

import something

./test.py:

import dir
# can now use dir.something

EDIT: забыл упомянуть, код в __init__.py выполняется при первом импорте модуля из этого каталога. Поэтому обычно это хорошее место для размещения любого кода инициализации на уровне пакета.

EDIT2: dgrant указал на возможную путаницу в моем образец. В __init__.pyimport something можно импортировать любой модуль, не обязательно из пакета. Например, мы можем заменить его на import datetime, то в нашем верхнем уровне test.py оба этих фрагмента будут работать:

import dir
print dir.datetime.datetime.now()

и

import dir.some_module_in_dir
print dir.datetime.datetime.now()

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

это просто личные предпочтения на самом деле, и имеет отношение к макету ваших модулей python.

скажем, у вас есть модуль под названием erikutils. Есть два способа, что это может быть модуль, либо у вас есть файл с именем erikutils.py на вашем sys.path или у вас есть каталог с именем erikutils на sys.path пустой __init__.py внутри него. Тогда предположим, у вас есть куча модулей под названием fileutils,procutils, parseutils и вы хотите, чтобы они были подмодулями под erikutils. Поэтому вы делаете некоторые файлы .py под названием fileutils.py, procutils.py, и parseutils.py:

erikutils
  __init__.py
  fileutils.py
  procutils.py
  parseutils.py

может быть, у вас есть несколько функций, которые просто не принадлежат в fileutils,procutils или parseutils модули. И допустим, вам не хочется создавать новый модуль под названием miscutils. И, вы хотели бы иметь возможность вызывать функцию следующим образом:

erikutils.foo()
erikutils.bar()

а чем занимаюсь

erikutils.miscutils.foo()
erikutils.miscutils.bar()

, потому что erikutils модуль-это каталог, а не файл, мы должны определить его функции внутри __init__.py.

в django, лучший пример, который я могу придумать это django.db.models.fields. Все классы полей django * определены в __init__.py на django / db / models / fields

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

обратите внимание, что вы можете использовать del команда, так что типичный __init__.py может выглядеть это:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

теперь, если вы решите разделить somemodule новая __init__.py может быть:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject

del somemodule1
del somemodule2

снаружи пакета все равно выглядит точно так же, как и раньше.