Добавление кода в __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__.py
import 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, четвертое издание, Стивен Ф. Лотт, Дасти Филлипс.