Ответы:
Это список открытых объектов этого модуля в интерпретации import *
. Он отменяет стандартное скрытие всего, что начинается с подчеркивания.
import *
(например, например tk
). Хорошей подсказкой, если это так, является наличие __all__
или имена, начинающиеся с подчеркивания в коде модуля.
tk
были выпущены сегодня (или даже в 2012 году), рекомендуемой практикой будет использование from tk import *
. Я думаю, что практика принята из-за инерции, а не преднамеренного дизайна.
Связано, но здесь явно не упомянуто, именно тогда, когда __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>
.
print(baz())
?
print(baz)
печатает что-то вроде <function baz at 0x7f32bc363c10>
тогдашних print(baz())
печатных изданийbaz
Объясните __all__ в Python?
Я продолжаю видеть
__all__
набор переменных в разных__init__.py
файлах.Что это делает?
__all__
?Он объявляет семантически «публичные» имена из модуля. Если есть имя __all__
, пользователи должны его использовать, и они могут ожидать, что оно не изменится.
Это также будет иметь программные последствия:
import *
__all__
в модуле, например module.py
:
__all__ = ['foo', 'Bar']
означает, что когда вы import *
из модуля, __all__
импортируются только те имена в :
from module import * # imports foo and Bar
Инструменты документирования и автозаполнения кода могут (на самом деле, должны) также проверять, __all__
какие имена показывать как доступные из модуля.
__init__.py
делает каталог пакетом PythonИз документов :
Эти
__init__.py
файлы необходимы , чтобы Python лечить каталоги как содержащие пакеты; это сделано для предотвращения непреднамеренного скрытия действительными модулями каталогов с общим именем, например, строки, которые появляются позже в пути поиска модулей.В простейшем случае
__init__.py
может быть просто пустой файл, но он также может выполнить код инициализации для пакета или установить__all__
переменную.
Таким образом, __init__.py
можно объявить __all__
для пакета .
Пакет обычно состоит из модулей, которые могут импортировать друг друга, но которые обязательно связаны вместе с __init__.py
файлом. Этот файл делает каталог настоящим пакетом Python. Например, скажем, у вас есть следующие файлы в пакете:
package
├── __init__.py
├── module_1.py
└── module_2.py
Давайте создадим эти файлы с помощью Python, чтобы вы могли следить за ними - вы можете вставить следующее в оболочку Python 3:
from pathlib import Path
package = Path('package')
package.mkdir()
(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")
package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")
package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")
И теперь вы представили полный API, который кто-то другой может использовать при импорте вашего пакета, например:
import package
package.foo()
package.Bar()
И в пакете не будет всех других деталей реализации, которые вы использовали при создании ваших модулей, загромождающих package
пространство имен.
__all__
в __init__.py
После дополнительной работы, может быть, вы решили, что модули слишком большие (например, много тысяч строк?) И должны быть разделены. Итак, вы делаете следующее:
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
Сначала создайте каталоги подпакетов с теми же именами, что и у модулей:
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
Переместите реализации:
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
создать __init__.py
s для подпакетов, которые объявляют __all__
для каждого:
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
И теперь у вас все еще есть API, предоставляемый на уровне пакета:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
И вы можете легко добавлять вещи в свой API, которыми вы можете управлять на уровне подпакета вместо уровня модуля подпакета. Если вы хотите добавить новое имя в API, просто обновите __init__.py
, например, в module_2:
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
И если вы не готовы к публикации Baz
в API верхнего уровня, на вашем верхнем уровне __init__.py
вы могли бы иметь:
from .module_1 import * # also constrained by __all__'s
from .module_2 import * # in the __init__.py's
__all__ = ['foo', 'Bar'] # further constraining the names advertised
и если ваши пользователи знают о доступности Baz
, они могут использовать его:
import package
package.Baz()
но если они не знают об этом, другие инструменты (например, pydoc ) не сообщат им.
Позже вы можете изменить это, когда будете Baz
готовы к прайм-тайм:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
сравнению с __all__
:По умолчанию Python экспортирует все имена, которые не начинаются с _
. Вы, конечно, можете положиться на этот механизм. Некоторые пакеты в стандартной библиотеке Python, на самом деле, действительно полагаться на это, но сделать это так, они псевдоним их импорта, например, в ctypes/__init__.py
:
import os as _os, sys as _sys
Использование _
соглашения может быть более элегантным, потому что оно удаляет избыточность именования имен снова. Но это добавляет избыточность для импорта (если у вас их много), и легко забыть делать это последовательно - и последнее, что вам нужно, - это бесконечно поддерживать то, что вы намеревались представлять только как детали реализации, просто потому что вы забыли поставить префикс _
при названии функции.
Я лично пишу в __all__
начале своего жизненного цикла разработки для модулей, чтобы другие, кто мог использовать мой код, знали, что они должны использовать, а не использовать.
Большинство пакетов в стандартной библиотеке также используют __all__
.
__all__
имеет смыслИмеет смысл придерживаться _
префиксного соглашения вместо того, чтобы __all__
:
export
декораторНедостатком использования __all__
является то, что вы должны написать имена функций и классов, которые экспортируются дважды - и информация хранится отдельно от определений. Мы могли бы использовать декоратор для решения этой проблемы.
Я получил идею для такого экспортного декоратора из выступления Дэвида Бизли об упаковке. Эта реализация хорошо работает в традиционном импортере CPython. Если у вас есть специальный хук импорта или система, я не гарантирую это, но если вы примете это, отрицать это довольно тривиально - вам просто нужно вручную добавить имена обратно в__all__
Так, например, в служебной библиотеке вы должны определить декоратор:
import sys
def export(fn):
mod = sys.modules[fn.__module__]
if hasattr(mod, '__all__'):
mod.__all__.append(fn.__name__)
else:
mod.__all__ = [fn.__name__]
return fn
и затем, где вы бы определили __all__
, вы делаете это:
$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.
@export
def foo(): pass
@export
def bar():
'bar'
def main():
print('main')
if __name__ == '__main__':
main()
И это прекрасно работает независимо от того, работает ли оно как основное или импортируется другой функцией.
$ cat > run.py
import main
main.main()
$ python run.py
main
И обеспечение API с import *
тоже будет работать:
$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported
$ python run.py
Traceback (most recent call last):
File "run.py", line 4, in <module>
main() # expected to error here, not exported
NameError: name 'main' is not defined
@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
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Помощь по модулю module1: ИМЯ module1 ФАЙЛ module1.py ДАННЫЕ a = 'A' b = 'B' c = 'C'
$ pydoc module2
Помощь по модулю module2: ИМЯ module2 ФАЙЛ module2.py ДАННЫЕ __all__ = ['a', 'b'] a = 'A' b = 'B'
Я заявляю, что __all__
во всех моих модулях, а также подчеркиваю внутренние детали, они действительно помогают при использовании вещей, которые вы никогда раньше не использовали в сеансах прямого перевода.
__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 распознает их. [ @Longpoke ]
Посмотрите, как 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__
настраивает *
импорт подстановочных знаков из пакета. [ @MartinStettner ]
Вот выдержка из Python MySQL Connector __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
импортируются только объекты, определенные в :
Если
__all__
не определен, то операторfrom sound.effects import *
имеет не импортировать все подмодули из пакетаsound.effects
в текущее пространство имен; он только гарантирует, что пакетsound.effects
был импортирован (возможно, с использованием любого кода инициализации__init__.py
), а затем импортирует все имена, определенные в пакете. Это включает любые имена, определенные (и явно загруженные подмодули)__init__.py
. Он также включает любые подмодули пакета, которые были явно загружены предыдущими операторами импорта.
Следует избегать импорта символов подстановки ... поскольку они [запутывают] читателей и многие автоматизированные инструменты.
[ PEP 8 , @ToolmakerSteve]
from <package> import *
не __all__
в __init__.py
том , что это не импортировать любой из модулей .
__init__.py
это был модуль . Но я не уверен, что это точно, или, в частности, если объекты с префиксом подчеркивания исключены. Кроме того, я более четко разделил разделы на МОДУЛИ и ПАКЕТЫ. Твои мысли?
Из (Неофициального) Python Reference Wiki :
Публичные имена, определенные модулем, определяются путем проверки пространства имен модуля на наличие имени
__all__
; если определено, это должна быть последовательность строк, имена которых определены или импортированы этим модулем. Приведенные имена__all__
являются общедоступными и должны существовать. Если__all__
не определено, набор открытых имен включает все имена, найденные в пространстве имен модуля, которые не начинаются с символа подчеркивания («_»).__all__
должен содержать весь публичный API. Он предназначен для предотвращения случайного экспорта элементов, которые не являются частью API (таких как библиотечные модули, которые были импортированы и использованы внутри модуля).
__all__
используется для документирования публичного API модуля Python. Хотя это необязательно, __all__
следует использовать.
Вот соответствующая выдержка из ссылки на язык Python :
Публичные имена, определенные модулем, определяются путем проверки пространства имен модуля на наличие имени
__all__
; если определено, это должна быть последовательность строк, имена которых определены или импортированы этим модулем. Приведенные имена__all__
являются общедоступными и должны существовать. Если__all__
не определен, набор открытых имен включает все имена, найденные в пространстве имен модуля, которые не начинаются с символа подчеркивания ('_').__all__
должен содержать весь публичный API. Он предназначен для предотвращения случайного экспорта элементов, которые не являются частью API (таких как библиотечные модули, которые были импортированы и использованы внутри модуля).
PEP 8 использует аналогичную формулировку, хотя также дает понять, что импортированные имена не являются частью общедоступного API, когда они __all__
отсутствуют:
Для лучшей поддержки самоанализа модули должны явно объявлять имена в своем публичном API, используя
__all__
атрибут. Установка__all__
в пустой список означает, что модуль не имеет публичного API.[...]
Импортированные имена всегда должны рассматриваться как детали реализации. Другие модули не должны полагаться на косвенный доступ к таким импортированным именам, если они не являются явно документированной частью API содержащего модуля, такого как
os.path
или__init__
модуль пакета, который предоставляет функциональность из подмодулей.
Кроме того, как указано в других ответах, __all__
используется для включения импорта групповых символов для пакетов :
Оператор импорта использует следующее соглашение: если
__init__.py
код пакета определяет именованный список__all__
, он считается списком имен модулей, которые следует импортировать приfrom package import *
обнаружении.
__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 здесь :
Глобальные имена переменных
(Будем надеяться, что эти переменные предназначены для использования только внутри одного модуля.) Соглашения примерно такие же, как и для функций.
Модули, разработанные для использования через,
from M import *
должны использовать__all__
механизм, предотвращающий экспорт глобальных файлов, или использовать более старую конвенцию, заключающуюся в добавлении префиксов для таких глобальных символов с подчеркиванием (что может потребоваться для указания того, что эти глобальные переменные являются «непубличными модулями»).
PEP8 предоставляет соглашения о кодировании для кода Python, включающего стандартную библиотеку в основном дистрибутиве Python. Чем больше вы будете следовать этому, тем ближе вы будете к первоначальному замыслу.
__all__
случае, если они__all__
присутствуют, не совсем скрыты; они могут быть замечены и доступны совершенно нормально, если вы знаете их имена. Только в случае «импорта *», который в любом случае не рекомендуется, различие имеет какой-либо вес.