Я смотрю, как работает модельная система в django, и заметил кое-что, чего не понимаю.
Я знаю, что вы создаете пустой __init__.py
файл, чтобы указать, что текущий каталог является пакетом. И что вы можете установить некоторую переменную, __init__.py
чтобы import * работал правильно.
Но django добавляет кучу операторов from ... import ... и определяет кучу классов внутри __init__.py
. Зачем? Разве это не просто беспорядочно? Есть ли причина, по которой этот код требуется __init__.py
?
__init__.py
django 1.8. Это было для более старой версии? если да, то какая версия?Ответы:
Все операции импорта
__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
, будь то импортированные модули, функции или классы, автоматически становятся доступными в пространстве имен пакета всякий раз, когда вы импортируете пакет или модуль в пакете.источник
__init__.py
Я действительно не рассматриваю код инициализации этих классов (но, возможно, я ошибаюсь в этом).__init__.py
неявно. Импортируя модули внутри__init__.py
, вы создаете циклический импорт.__init__.py
Не будет выполнена полностью , прежде чем одного такого импорта. Безопаснее оставить__init__.py
пустым.__init__.py
файлам. Если бы у вас был файл, вdir/other.py
котором было что-то подобное,from datetime import datetime
вы также могли бы позвонитьdir.other.datetime.now()
или дажеfrom dir.other import datetime
.На самом деле это просто личные предпочтения, и они связаны с компоновкой ваших модулей Python.
Допустим, у вас есть модуль с именем
erikutils
. Есть два способа , которыми это может быть модулем, либо у вас есть файл с именем erikutils.py на своем контекстуальномsys.path
или у вас есть каталог с именем erikutils на вашемsys.path
с пустым__init__.py
файлом внутри него. Тогда скажем , у вас есть куча модулей , называемыхfileutils
,procutils
,parseutils
и вы желаете, чтобы быть суб-модулей подerikutils
. Таким образом , вы сделать некоторые .py файлы , называемые fileutils.py , procutils.py и parseutils.py :Может быть , у вас есть несколько функций , которые просто не принадлежат в
fileutils
,procutils
илиparseutils
модулях. Допустим, вам не хочется создавать новый модуль с именемmiscutils
. И вы хотите иметь возможность вызывать функцию следующим образом:вместо того, чтобы делать
Так как
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
).источник
something
может быть внешний модуль, dir.something будет работать. Спасибо за комментарий, отредактирую свой пост, чтобы было понятнее.Использование
__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
Снаружи упаковка выглядит так же, как и раньше.
источник
import <pack>.somemodule1
прямой доступ к нему . Вы можете импортировать только<pack>
объекты, определенные или импортированные в его__init__.py
, и не удаленные подмодули.