Відповіді:
Це список публічних об'єктів цього модуля, як їх інтерпретують 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__.pys для підпакетів, які декларують __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__є, точно не приховані; Ви можете бачити та отримувати доступ до них абсолютно нормально, якщо ви знаєте їхні імена. Лише у випадку "імпорту *", який у будь-якому разі не рекомендується, розмежування має будь-яку вагу.