Добавление кода в __init__.py
-
02-07-2019 - |
Вопрос
Я смотрю на то, как работает система моделей в Джанго, и заметил кое-что, чего не понимаю.
Я знаю, что ты создаешь пустое __init__.py
file, чтобы указать, что текущий каталог является пакетом.И что вы можете установить некоторую переменную в __init__.py
чтобы импорт * работал правильно.
Но django добавляет кучу из...Импортировать ...операторы и определяет кучу классов в __init__.py
.Почему?Разве это не приводит к тому, что все выглядит беспорядочно?Есть ли причина, по которой этот код требуется в __init__.py
?
Решение
Весь импорт в __init__.py
становятся доступными при импорте пакета (каталога), который его содержит.
Пример:
./dir/__init__.py
:
import something
./test.py
:
import dir
# can now use dir.something
РЕДАКТИРОВАТЬ:забыл упомянуть, код в __init__.py
запускается при первом импорте любого модуля из этого каталога.Так что обычно это хорошее место для размещения любого кода инициализации на уровне пакета.
РЕДАКТИРОВАТЬ2:Грант указал на возможную путаницу в моем примере.В __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
или у вас есть каталог под названием Эрикутилс на ваше 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.db.models.fields
.ВСЕ классы полей django *определены в __init__.py
файл в Джанго/БД/модели/поля каталог.Я думаю, они сделали это потому, что не хотели впихивать все в гипотетическую картину. django/db/models/fields.py модель, поэтому они разделили ее на несколько подмодулей (связанный.py, файлы.py, например) и засунули сделанные определения *Field в сам модуль полей (следовательно, __init__.py
).
Используя __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
Внешне упаковка по-прежнему выглядит так же, как и раньше.