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

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

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

Но django добавляет несколько операторов from... import... и определяет несколько классов в __init__.py, Зачем? Разве это не делает вещи беспорядочными? Есть ли причина, по которой этот код требуется в __init__.py?

4 ответа

Решение

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

Пример:

./dir/__init__.py:

import something

./test.py:

import dir
# can now use dir.something

РЕДАКТИРОВАТЬ: забыл упомянуть, код в __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 *Field определены в __init__.pyфайл в каталоге django/db/models/fields. Я думаю, что они сделали это, потому что они не хотели втиснуть все в гипотетическую модель django/db/models/fields.py, поэтому они разделили ее на несколько подмодулей (related.py, files.py, например) и они вставили сделанные * определения полей в сам модуль полей (следовательно, __init__.py).

С использованием __init__.py Файл позволяет сделать внутреннюю структуру пакета невидимой извне. Если внутренняя структура изменяется (например, из-за того, что вы разбили один жирный модуль на два), вам нужно только настроить __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

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

«Однако мы рекомендуем не размещать много кода в файле. Программисты не ожидают, что в этом файле будет происходить настоящая логика, как и в случае с from x import *, это может сбить их с толку, если они ищут объявление определенного фрагмента кода и не могут его найти, пока не проверят __init__.py. "

-- Объектно-ориентированное программирование на Python, четвертое издание, Стивен Ф. Лотт, Дасти Филлипс.

Другие вопросы по тегам