Может ли кто-нибудь объяснить __all__ в Python?

Я использую Python все больше и больше и продолжаю видеть переменную __all__, установленную в разных файлах __init__.py. Может кто-нибудь объяснить, что это значит?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1 149
0
358 647
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

Это список общедоступных объектов этого модуля в интерпретации import *. Он отменяет стандартное скрытие всего, что начинается с подчеркивания.

Объекты, начинающиеся с подчеркивания или не упомянутые в __all__, если присутствует __all__, не являются полностью скрытыми; их можно увидеть и получить к ним доступ совершенно нормально, если вы знаете их имена. Только в случае «import *», который в любом случае не рекомендуется, различие имеет какой-либо вес.

Brandon Rhodes 08.12.2009 21:40

@BrandonRhodes: это тоже не совсем так: рекомендуется импортировать только те модули, которые, как вы знаете, предназначены для import * (например, tk). Хороший намек в этом случае - наличие __all__ или имен, начинающихся с подчеркивания в коде модуля.

flying sheep 08.04.2012 02:15

Общедоступные и внутренние интерфейсы - python.org/dev/peps/pep-0008/#id50. Чтобы лучше поддерживать самоанализ, модули должны явно объявлять имена в своем общедоступном API с помощью атрибута __all__. Установка __all__ в пустой список означает, что у модуля нет общедоступного API.

debug 10.04.2018 18:20

Я не уверен, что если бы tk был выпущен сегодня (или даже в 2012 году), рекомендуемой практикой было бы использование from tk import *. Я думаю, что такая практика принята по инерции, а не намеренно.

chepner 06.11.2019 18:36

От (Неофициальный) Справочник по Python вики:

The public names defined by a module are determined by checking the module's namespace for a variable named __all__; if defined, it must be a sequence of strings which are names defined or imported by that module. The names given in __all__ are all considered public and are required to exist. If __all__ is not defined, the set of public names includes all names found in the module's namespace which do not begin with an underscore character ("_"). __all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module).

Указанная ссылка мертва. но нашел дословный текст на vdocuments.net/… и здесь: dokumen.tips/documents/reference-567bab8d6118a.html

JayRizzo 06.08.2018 06:09

Связано, но не упомянуто здесь явно, когда используется __all__. Это список строк, определяющих, какие символы в модуле будут экспортированы при использовании from <module> import * в модуле.

Например, следующий код в foo.py явно экспортирует символы bar и baz:

__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

Затем эти символы можно импортировать следующим образом:

from foo import *

print(bar)
print(baz)

# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

Если указанный выше __all__ закомментирован, этот код будет выполнен до завершения, поскольку поведение import * по умолчанию заключается в импорте всех символов, которые не начинаются с подчеркивания, из заданного пространства имен.

Ссылка: https://docs.python.org/tutorial/modules.html#importing-from-a-package

ПРИМЕЧАНИЕ:__all__ влияет только на поведение from <module> import *. Члены, не упомянутые в __all__, по-прежнему доступны извне модуля и могут быть импортированы с помощью from <module> import <member>.

разве мы не должны печатать baz как print(baz())?

John Cole 24.02.2020 04:24

@JohnCole baz - это функциональный объект, а baz () запускает функциональный объект.

Bhanu Tez 30.05.2020 12:14

@BhanuTez именно так. Итак, print(baz) печатает что-то вроде <function baz at 0x7f32bc363c10>, тогда как print(baz()) печатает baz.

John Cole 01.06.2020 01:35

Цель состоит в том, чтобы проиллюстрировать, что символы экспортируются. Выполняет он функцию или нет - вторично.

Alec Thomas 22.07.2020 07:29

Меня озадачивает то, что до сих пор нет способа заполнить __all__, напрямую ссылаясь на функции / объекты. Вместо этого мы должны вводить их имена и исправлять их индивидуально каждый раз, когда имя меняется. Кажется, очень подвержен ошибкам для активных кодовых баз.

Julio Cezar Silva 07.08.2020 18:01

@JulioCezarSilva немного не по теме, но стоит отметить, что для классов и функций вы можете использовать свойство __name__

phsyron 29.09.2020 20:45

Это также меняет то, что покажет pydoc:

module1.py

a = "A"
b = "B"
c = "C"

module2.py

__all__ = ['a', 'b']

a = "A"
b = "B"
c = "C"

$ pydoc module1

Help on module module1:

NAME
    module1

FILE
    module1.py

DATAa = 'A'
    b = 'B'
    c = 'C'

$ pydoc module2

Help on module module2:

NAME
    module2

FILE
    module2.py

DATA__all__ = ['a', 'b']
    a = 'A'
    b = 'B'

Я объявляю __all__ во всех своих модулях, а также подчеркиваю внутренние детали, они действительно помогают при использовании вещей, которые вы никогда раньше не использовали в сеансах реального интерпретатора.

Я просто добавляю это, чтобы быть точным:

Все остальные ответы относятся к модули. В исходном вопросе явно упоминается __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__ он не будет автоматически импортировать модули, определенные в каталоге пакета.

Nikratio 20.07.2014 23:37

Когда все содержит [foo, bar] и в файле test.py, если мы используем: from package import *, то импортируются ли foo и bar в локальное пространство имен test.py или в собственное пространство имен foo и bars?

variable 12.10.2019 08:26

__all__ настраивает * в from <module> import *

__all__ настраивает * в from <package> import *


модуль - это файл .py, предназначенный для импорта.

упаковка - это каталог с файлом __init__.py. Пакет обычно содержит модули.


МОДУЛИ

""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__ позволяет людям узнать "общедоступные" функции модуль.[@AaronHall] Кроме того, pydoc распознает их.

из импорта модуль *

Посмотрите, как swiss и cheddar переносятся в локальное пространство имен, но не gouda:

>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined

Без __all__ любой символ (который не начинается с подчеркивания) был бы доступен.


Импорт без * не затрагивается __all__


импорт модуль

>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

из модуль импортировать имена

>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

импортировать модуль как местное имя

>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

ПАКЕТЫ

В файле __init__.pyупаковка__all__ находится список строк с именами общедоступных модулей или других объектов. Эти функции доступны для импорта с подстановочными знаками. Как и в случае с модулями, __all__ настраивает * при импорте подстановочных знаков из пакета.

Вот выдержка из Соединитель Python MySQL__init__.py:

__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

    # Some useful constants
    'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
    'HAVE_CEXT',

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

Случай по умолчанию, звездочка без __all__ для пакета, сложен, потому что очевидное поведение было бы дорогостоящим: использовать файловую систему для поиска всех модулей в пакете. Вместо этого при чтении документов импортируются только объекты, определенные в __init__.py:

If __all__ is not defined, the statement from sound.effects import * does not import all submodules from the package sound.effects into the current namespace; it only ensures that the package sound.effects has been imported (possibly running any initialization code in __init__.py) and then imports whatever names are defined in the package. This includes any names defined (and submodules explicitly loaded) by __init__.py. It also includes any submodules of the package that were explicitly loaded by previous import statements.


И, наконец, почитаемая традиция ответов на вопросы о переполнении стека, профессоров и специалистов по всему миру - это упрек Bon Mot за то, что они задают вопрос в первую очередь:

Wildcard imports ... should be avoided, as they [confuse] readers and many automated tools.

[@Longpoke]

Мне очень нравится этот ответ, но мне не хватает информации о том, какое поведение по умолчанию для from <package> import * без __all__ в __init__.py, то есть не импортировать ни один из модулей.

radzak 21.03.2019 18:09

Спасибо @Jatimir, я как мог уточнил, не проводя экспериментов. Я почти хотел сказать, что этот случай (звездочка без всего для пакета) ведет себя так же как если бы __init__.py был модулем. Но я не уверен, что это правильно, или, в частности, исключены ли объекты с префиксом подчеркивания. Также я более четко разделил разделы на МОДУЛИ и ПАКЕТЫ. Твои мысли?

Bob Stein 21.03.2019 20:55

__all__ используется для документирования общедоступного API модуля Python. Хотя это необязательно, следует использовать __all__.

Вот соответствующий отрывок из справочник по языку Python:

The public names defined by a module are determined by checking the module’s namespace for a variable named __all__; if defined, it must be a sequence of strings which are names defined or imported by that module. The names given in __all__ are all considered public and are required to exist. If __all__ is not defined, the set of public names includes all names found in the module’s namespace which do not begin with an underscore character ('_'). __all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module).

PEP 8 использует аналогичную формулировку, хотя также дает понять, что импортированные имена не являются частью общедоступного API, когда __all__ отсутствует:

To better support introspection, modules should explicitly declare the names in their public API using the __all__ attribute. Setting __all__ to an empty list indicates that the module has no public API.

[...]

Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module's API, such as os.path or a package's __init__ module that exposes functionality from submodules.

Кроме того, как указано в других ответах, __all__ используется для включения импорт подстановочных знаков для пакетов:

The import statement uses the following convention: if a package’s __init__.py code defines a list named __all__, it is taken to be the list of module names that should be imported when from package import * is encountered.

Краткий ответ

__all__ влияет на утверждения from <module> import *.

Длинный ответ

Рассмотрим этот пример:

foo
├── bar.py
└── __init__.py

В 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:

from foo import *

* требует, чтобы все атрибуты модуля foo (кроме тех, которые начинаются с подчеркивания) были связаны как глобальные переменные в импортирующем модуле. Когда foo имеет атрибут __all__, значение атрибута представляет собой список имен, связанных этим типом оператора from.

Если foo является упаковка и его __init__.py определяет список с именем __all__, он считается списком имен подмодулей, которые должны быть импортированы при обнаружении from foo import *. Если __all__ не определен, оператор from foo import * импортирует любые имена, определенные в пакете. Сюда входят любые имена, определенные (и явно загруженные подмодули) __init__.py.

Обратите внимание, что __all__ не обязательно должен быть списком. Согласно документации по Заявление import, если он определен, __all__ должен быть последовательность строк, которые являются именами, определенными или импортированными модулем. Таким образом, вы также можете использовать кортеж для спасти некоторых циклов памяти и процессора. Только не забудьте запятую, если модуль определяет одно публичное имя:

__all__ = ('some_name',)

См. Также Почему «импорт *» - это плохо?

Это определено в PEP8 здесь:

Global Variable Names

(Let's hope that these variables are meant for use inside one module only.) The conventions are about the same as those for functions.

Modules that are designed for use via from M import * should use the __all__ mechanism to prevent exporting globals, or use the older convention of prefixing such globals with an underscore (which you might want to do to indicate these globals are "module non-public").

PEP8 предоставляет соглашения о кодировании для кода Python, составляющего стандартную библиотеку в основном дистрибутиве Python. Чем больше вы следуете этому, тем ближе вы к первоначальному замыслу.

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