Сообщить об ошибке.

Переменная __all__ в пакетах и модулях в Python

Управление импортом модулей из пакета

В материале "Инструкция from <modulle> import <names>" рассматривался случай использования конструкции from <module> import *, когда все объекты модуля импортируются в область видимости вызывающей стороны, за исключением тех, чьи имена начинаются с символа подчеркивания.

Аналогичное утверждение для пакета выглядит следующим образом from <package> import *. Попробуем сделать импорт всех модулей пакета из примера материала "Инициализация пакета с модулями":

>>> dir()
# ['__annotations__', '__builtins__', '__doc__', '__loader__', 
# '__name__', '__package__', '__spec__']

>>> from pkg import *
>>> dir()
# ['__annotations__', '__builtins__', '__doc__', '__loader__', 
# '__name__', '__package__', '__spec__']

По умолчанию инструкция from <package> import * ничего не импортирует.

Python следует соглашению: если __init__.py файл в каталоге пакета содержит список с именем __all__, он считается списком модулей, которые должны быть импортированы при обнаружении инструкции from <package> import *.

Изменим __init__.py в каталоге pkg следующим образом:

__all__ = [
        'mod1',
        'mod2'
        ]
var_init = ['one', 'two', 'three']

Попробуем сделать импорт всех модулей пакета pkg еще раз.

>>> from pkg import *
>>> dir()
# ['__annotations__', '__builtins__', '__doc__', '__loader__',
# '__name__', '__package__', '__spec__', 'mod1', 'mod2']

>>> mod2.bar()
# Модуль 2, функция bar()
>>> mod1.foo()
# Модуль 1, функция foo(), var_init = ['one', 'two', 'three']

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

Кстати, __all__ также может быть определена в модуле и служит той же цели: контролировать то, что импортируется с помощью конструкции import *.

Изменим mod1.py следующим образом:

__all__ = ['foo']

def foo():
    from pkg import var_init
    print('Модуль 1, функция foo())

def other():
    print('Модуль 1, функция other())

Теперь конструкция from pkg.mod1 import * будет импортировать только то, что содержится в __all__:

>>> from pkg.mod1 import *
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__',
'__package__', '__spec__', 'foo']

>>> foo()
# Модуль 1, функция foo()

>>> other()
# Traceback (most recent call last):
# ...
# NameError: name 'other' is not defined

Функция foo() теперь определена в локальном пространстве имен, а функция other() - нет, потому что не находится в списке __all__.

Таким образом, переменная __all__ используется как пакетами, так и модулями для управления тем, что импортируется при использовании конструкции import *. Но поведение по умолчанию отличается:

  • Для пакета, когда __all__ не определен, import * ничего не импортирует.
  • Для модуля, когда __all__ не определен, import * импортирует все, кроме имен, начинающихся с символа подчеркивания.