Оператор import в Python — способы импортирования

В этом уроке вы изучите возможности оператора импорта в Python и то, как они работают «под капотом».

Содержание

Импорт модулей в Python

Когда вы импортируете модуль, Python делает две вещи:

  • Сначала проверяет, был ли модуль загружен и кэширован в sys.modules. Если нет, он выполнит модуль и создаст ссылку на объект модуля.
  • Во-вторых, добавляет имя модуля в глобальное пространство имен, ссылающееся на тот же объект модуля.

Следующая программа импортирует модуль math и распечатывает математический объект math в sys.modules и глобальном пространстве имен:

import sys
import math


print('sys.modules:', hex(id(sys.modules['math'])))

if 'math' in globals():
    print('globals: ', hex(id(globals()['math'])))

Выход:

sys.modules: 0x20456766590
globals:  0x20456766590

Как видите, математическая переменная ссылается на один и тот же объект модуля.

Если вы импортируете math во второй раз, Python не выполнит модуль повторно, а получит его из кэша sys.modules.

Импорт объекта

Когда вы импортируете объект (функцию, класс и т. д.) из модуля в Python, необходимо сделать следующее:

  • Сначала проверьте, был ли модуль загружен и кэширован в sys.modules. Если нет, он выполнит модуль и создаст ссылку на объект модуля.
  • Во-вторых, добавьте объект импорта в глобальное пространство имен.

В этом случае Python добавляет в глобальное пространство имен не переменную, ссылающуюся на модуль, а переменную, ссылающуюся на импортируемый объект.

В следующем примере функция ceil импортируется из объекта math:

import sys
from pprint import pprint
from math import ceil

print('sys.modules:', hex(id(sys.modules['math'])))

pprint(globals())

Выход:

sys.modules: 0x11d659c2130
{'__annotations__': {},
 '__builtins__': <module 'builtins'(built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000011D65A008E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'ceil': <built-in function ceil>,
 'pprint': <function pprint at 0x0000011D661C4040>,
 'sys': <module 'sys'(built-in)>}

В этом примере Python загружает математический модуль в sys.modules. Однако он создает ссылку только на функцию ceil, а не на объект модуля math в глобальном пространстве имен.

Импорт объекта из модуля как object_alias

Когда вы загружаете объект из модуля и используете псевдоним в Python, сделайте следующее:

  • Сначала проверьте, был ли модуль загружен и кэширован в sys.modules. Если нет, он выполнит модуль и создаст ссылку на объект модуля.
  • Во-вторых, создайте псевдоним, ссылающийся на импортируемый объект, и добавьте его в глобальное пространство имен.

Следующий пример импортирует функцию ceil из модуля math и использует псевдоним:

import sys
from math import ceil as ceiling

print('sys.modules:', hex(id(sys.modules['math'])))
print('globals:', hex(id(globals()['ceiling'])))

Выход:

sys.modules: 0x1cc4f244ae0
{'__annotations__': {},
 '__builtins__': <module 'builtins'(built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CC4EA708E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'ceiling': <built-in function ceil>,
 'pprint': <function pprint at 0x000001CC4F234040>,
 'sys': <module 'sys'(built-in)>}

Конструкция from module import *

Когда вы импортируете все из модуля, Python сделает следующее:

  • Проверит, был ли модуль загружен и кэширован в sys.modules. Если нет, он выполнит модуль и создаст ссылку на объект модуля.
  • Во-вторых, добавит все символы из модуля в глобальное пространство имен.

Например, следующий код импортирует все объекты из модуля math:

import sys
from pprint import pprint
from math import *

print('sys.modules:', hex(id(sys.modules['math'])))
pprint(globals())

Выход:

sys.modules: 0x1e1ebf24b30
{'__annotations__': {},
 '__builtins__': <module 'builtins'(built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E1EB7408E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'acos': <built-in function acos>,
 'acosh': <built-in function acosh>,
 'asin': <built-in function asin>,

....
 'tau': 6.283185307179586,
 'trunc': <built-in function trunc>}

Как ясно видно из вывода, Python добавляет все функции из модуля math в глобальные пространства имен. В этом случае, если в глобальном пространстве имен существуют какие-либо символы, Python заменит их ссылки.

Это часто приводит к ошибкам, которые трудно отследить.

Заблуждение об операторе import в Python

Одним из наиболее распространенных заблуждений относительно оператора импорта является то, что многие считают следующее утверждение:

from math import ceil

более эффективен, чем:

import math

Потому что первый оператор импортирует только функцию ячейки, а второй оператор импортирует весь математический модуль.

Однако в обоих случаях Python загружает весь модуль math.

Первый оператор создает символ, ссылающийся на функцию ceil из math-модуля, а второй оператор создает математический символ, ссылающийся на объект математического модуля.

Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *