Відповіді:
Це список публічних об'єктів цього модуля, як їх інтерпретують 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']
""")
А тепер у вас все ще передбачена програма на рівні пакету:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
Ви можете легко додати речі до свого API, якими ви зможете керувати на рівні субпакеті замість рівня модуля підпаку. Якщо ви хочете додати нове ім'я в API, просто оновіть його __init__.py
, наприклад, у модулі_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
__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__
нього не буде автоматично імпортуватися жоден модуль, визначений в каталозі пакета.
Це також змінює те, що підок покаже:
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc модуль1
Довідка по модулю модуля1: ІМ’Я модуль1 ФАЙЛ module1.py DATA a = 'A' b = 'B' c = 'C'
$ pydoc модуль2
Довідка по модулю module2: ІМ’Я модуль2 ФАЙЛ 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 ] Також підок розпізнає їх. [ @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 __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 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__
є, точно не приховані; Ви можете бачити та отримувати доступ до них абсолютно нормально, якщо ви знаєте їхні імена. Лише у випадку "імпорту *", який у будь-якому разі не рекомендується, розмежування має будь-яку вагу.