Я использую Python все больше и больше, и я продолжаю видеть __all__
набор переменных в разных __init__.py
файлах. Может кто-нибудь объяснить, что это делает?
python
syntax
namespaces
varikin
источник
источник
__all__
случае, если они__all__
присутствуют, не совсем скрыты; они могут быть замечены и доступны совершенно нормально, если вы знаете их имена. Только в случае «импорта *», который в любом случае не рекомендуется, различие имеет какой-либо вес.import *
(например, напримерtk
). Хорошей подсказкой, если это так, является наличие__all__
или имена, начинающиеся с подчеркивания в коде модуля.tk
были выпущены сегодня (или даже в 2012 году), рекомендуемой практикой будет использованиеfrom tk import *
. Я думаю, что практика принята из-за инерции, а не преднамеренного дизайна.Связано, но здесь явно не упомянуто, именно тогда, когда
__all__
используется. Это список строк, определяющих, какие символы в модуле будут экспортироваться приfrom <module> import *
использовании в модуле.Например, следующий код
foo.py
явно экспортирует символыbar
иbaz
:Эти символы затем можно импортировать так:
Если
__all__
вышеприведенное закомментировано, этот код будет выполняться до конца, поскольку поведение по умолчаниюimport *
заключается в том, чтобы импортировать все символы, которые не начинаются с подчеркивания, из заданного пространства имен.Ссылка: https://docs.python.org/tutorial/modules.html#importing-from-a-package
ПРИМЕЧАНИЕ:
__all__
влияетfrom <module> import *
только на поведение. Члены, которые не упомянуты, по-__all__
прежнему доступны извне модуля и могут быть импортированы с помощьюfrom <module> import <member>
.источник
print(baz())
?print(baz)
печатает что-то вроде<function baz at 0x7f32bc363c10>
тогдашнихprint(baz())
печатных изданийbaz
Что делает
__all__
?Он объявляет семантически «публичные» имена из модуля. Если есть имя
__all__
, пользователи должны его использовать, и они могут ожидать, что оно не изменится.Это также будет иметь программные последствия:
import *
__all__
в модуле, напримерmodule.py
:означает, что когда вы
import *
из модуля,__all__
импортируются только те имена в :Инструменты документации
Инструменты документирования и автозаполнения кода могут (на самом деле, должны) также проверять,
__all__
какие имена показывать как доступные из модуля.__init__.py
делает каталог пакетом PythonИз документов :
Таким образом,
__init__.py
можно объявить__all__
для пакета .Управление API:
Пакет обычно состоит из модулей, которые могут импортировать друг друга, но которые обязательно связаны вместе с
__init__.py
файлом. Этот файл делает каталог настоящим пакетом Python. Например, скажем, у вас есть следующие файлы в пакете:Давайте создадим эти файлы с помощью Python, чтобы вы могли следить за ними - вы можете вставить следующее в оболочку Python 3:
И теперь вы представили полный API, который кто-то другой может использовать при импорте вашего пакета, например:
И в пакете не будет всех других деталей реализации, которые вы использовали при создании ваших модулей, загромождающих
package
пространство имен.__all__
в__init__.py
После дополнительной работы, может быть, вы решили, что модули слишком большие (например, много тысяч строк?) И должны быть разделены. Итак, вы делаете следующее:
Сначала создайте каталоги подпакетов с теми же именами, что и у модулей:
Переместите реализации:
создать
__init__.py
s для подпакетов, которые объявляют__all__
для каждого:И теперь у вас все еще есть API, предоставляемый на уровне пакета:
И вы можете легко добавлять вещи в свой API, которыми вы можете управлять на уровне подпакета вместо уровня модуля подпакета. Если вы хотите добавить новое имя в API, просто обновите
__init__.py
, например, в module_2:И если вы не готовы к публикации
Baz
в API верхнего уровня, на вашем верхнем уровне__init__.py
вы могли бы иметь:и если ваши пользователи знают о доступности
Baz
, они могут использовать его:но если они не знают об этом, другие инструменты (например, pydoc ) не сообщат им.
Позже вы можете изменить это, когда будете
Baz
готовы к прайм-тайм:Префикс по
_
сравнению с__all__
:По умолчанию Python экспортирует все имена, которые не начинаются с
_
. Вы, конечно, можете положиться на этот механизм. Некоторые пакеты в стандартной библиотеке Python, на самом деле, действительно полагаться на это, но сделать это так, они псевдоним их импорта, например, вctypes/__init__.py
:Использование
_
соглашения может быть более элегантным, потому что оно удаляет избыточность именования имен снова. Но это добавляет избыточность для импорта (если у вас их много), и легко забыть делать это последовательно - и последнее, что вам нужно, - это бесконечно поддерживать то, что вы намеревались представлять только как детали реализации, просто потому что вы забыли поставить префикс_
при названии функции.Я лично пишу в
__all__
начале своего жизненного цикла разработки для модулей, чтобы другие, кто мог использовать мой код, знали, что они должны использовать, а не использовать.Большинство пакетов в стандартной библиотеке также используют
__all__
.Когда избегать
__all__
имеет смыслИмеет смысл придерживаться
_
префиксного соглашения вместо того, чтобы__all__
:export
декораторНедостатком использования
__all__
является то, что вы должны написать имена функций и классов, которые экспортируются дважды - и информация хранится отдельно от определений. Мы могли бы использовать декоратор для решения этой проблемы.Я получил идею для такого экспортного декоратора из выступления Дэвида Бизли об упаковке. Эта реализация хорошо работает в традиционном импортере CPython. Если у вас есть специальный хук импорта или система, я не гарантирую это, но если вы примете это, отрицать это довольно тривиально - вам просто нужно вручную добавить имена обратно в
__all__
Так, например, в служебной библиотеке вы должны определить декоратор:
и затем, где вы бы определили
__all__
, вы делаете это:И это прекрасно работает независимо от того, работает ли оно как основное или импортируется другой функцией.
И обеспечение API с
import *
тоже будет работать:источник
@export
декоратор.__init__.py
и использования__all__
__all__
это правильно.__all__
тоже должны сгенерировать свой - но тогда я бы сказал, что у вас нестабильный API ... Это было бы что-то для проведения всесторонних приемочных тестов.module_1
иmodule_2
; нормально ли включать явноеdel module_1
в__init__.py
? Я ошибаюсь, если думаю, что это стоит того?Я просто добавляю это, чтобы быть точным:
Все остальные ответы относятся к модулям . Оригинальный вопрос явно упоминается
__all__
в__init__.py
файлах, так что речь идет о пакетах Python .Как правило,
__all__
вступает в действие только при использованииfrom xxx import *
вариантаimport
оператора. Это относится как к пакетам, так и к модулям.Поведение модулей объясняется в других ответах. Точное поведение для пакетов подробно описано здесь .
Короче говоря,
__all__
на уровне пакета выполняется примерно то же самое, что и для модулей, за исключением того, что он работает с модулями в пакете (в отличие от указания имен внутри модуля ). Так__all__
указывает все модули, которые должны быть загружены и импортированы в текущее пространство имен при использованииfrom package import *
.Большая разница в том, что когда вы опускаете объявление
__all__
в пакете__init__.py
, операторfrom package import *
вообще ничего не импортирует (с исключениями, объясненными в документации, см. Ссылку выше).С другой стороны, если вы опустите
__all__
в модуле, «импортированный по звездам» будет импортировать все имена (не начинающиеся с подчеркивания), определенные в модуле.источник
from package import *
будет по-прежнему импортировать все, что определено в__init__.py
, даже если нетall
. Важным отличием является то, что без__all__
него не будут автоматически импортироваться какие-либо модули, определенные в каталоге пакета.Это также меняет то, что pydoc покажет:
module1.py
module2.py
$ pydoc module1
$ pydoc module2
Я заявляю, что
__all__
во всех моих модулях, а также подчеркиваю внутренние детали, они действительно помогают при использовании вещей, которые вы никогда раньше не использовали в сеансах прямого перевода.источник
__all__
настраивает*
вfrom <module> import *
__all__
настраивает*
вfrom <package> import *
Модуль представляет собой
.py
файл, используемый для импорта.Пакет представляет собой каталог с
__init__.py
файлом. Пакет обычно содержит модули.МОДУЛИ
__all__
позволяет людям знать «публичные» функции модуля . [ @AaronHall ] Кроме того, Pydoc распознает их. [ @Longpoke ]из модуля импорта *
Посмотрите, как
swiss
иcheddar
заносятся в локальное пространство имен, но неgouda
:Без
__all__
, любой символ (который не начинается с подчеркивания) был бы доступен.Импорт без
*
не затронут__all__
модуль импорта
из модуля импорта имен
импортировать модуль как локальное имя
ПАКЕТЫ
В
__init__.py
файле пакета__all__
находится список строк с именами открытых модулей или других объектов. Эти функции доступны для импорта по шаблону. Как и в случае с модулями,__all__
настраивает*
импорт подстановочных знаков из пакета. [ @MartinStettner ]Вот выдержка из Python MySQL Connector
__init__.py
:Случай по умолчанию, звездочка без
__all__
пакета , сложен, потому что очевидное поведение будет дорого: использовать файловую систему для поиска всех модулей в пакете. Вместо этого при чтении документов__init__.py
импортируются только объекты, определенные в :[ PEP 8 , @ToolmakerSteve]
источник
from <package> import *
не__all__
в__init__.py
том , что это не импортировать любой из модулей .__init__.py
это был модуль . Но я не уверен, что это точно, или, в частности, если объекты с префиксом подчеркивания исключены. Кроме того, я более четко разделил разделы на МОДУЛИ и ПАКЕТЫ. Твои мысли?Из (Неофициального) Python Reference Wiki :
источник
__all__
используется для документирования публичного API модуля Python. Хотя это необязательно,__all__
следует использовать.Вот соответствующая выдержка из ссылки на язык Python :
PEP 8 использует аналогичную формулировку, хотя также дает понять, что импортированные имена не являются частью общедоступного API, когда они
__all__
отсутствуют:Кроме того, как указано в других ответах,
__all__
используется для включения импорта групповых символов для пакетов :источник
Короткий ответ
__all__
влияет наfrom <module> import *
высказывания.Длинный ответ
Рассмотрим этот пример:
В
foo/__init__.py
:(Неявный) Если мы не определим
__all__
, тоfrom foo import *
будет импортировать только имена, определенные вfoo/__init__.py
.(Явный) Если мы определим
__all__ = []
, тоfrom foo import *
ничего не будем импортировать.(Явный) Если мы определим
__all__ = [ <name1>, ... ]
, тоfrom foo import *
будет импортировать только эти имена.Обратите внимание, что в неявном случае python не будет импортировать имена, начинающиеся с
_
. Однако вы можете принудительно импортировать такие имена, используя__all__
.Вы можете просмотреть документ Python здесь .
источник
__all__
влияет какfrom foo import *
работает.Код, который находится внутри тела модуля (но не в теле функции или класса), может использовать звездочку (
*
) вfrom
выражении:Эти
*
запросы , что все атрибуты модуляfoo
( за исключением тех , кто начинает с подчеркиванием) быть связаны как глобальные переменные в импортирующей модуле. Когдаfoo
есть атрибут__all__
, значением атрибута является список имен, которые связаны с этим типомfrom
оператора.Если
foo
это пакет, и он__init__.py
определяет список__all__
имен, он считается списком имен подмодулей, которые следует импортировать приfrom foo import *
обнаружении. Если__all__
не определено, операторfrom foo import *
импортирует любые имена, определенные в пакете. Это включает любые имена, определенные (и явно загруженные подмодули)__init__.py
.Обратите внимание, что
__all__
это не обязательно должен быть список. Согласно документации поimport
инструкции , если она определена,__all__
должна быть последовательность строк , имена которых определены или импортированы модулем. Таким образом, вы также можете использовать кортеж для экономии памяти и циклов ЦП. Не забывайте запятую, если модуль определяет одно публичное имя:Смотрите также Почему «импорт *» плох?
источник
Это определено в PEP8 здесь :
PEP8 предоставляет соглашения о кодировании для кода Python, включающего стандартную библиотеку в основном дистрибутиве Python. Чем больше вы будете следовать этому, тем ближе вы будете к первоначальному замыслу.
источник