June 8, 2020

Глубокое изучение модулей

Продолжим знакомиться с системой модулей языка Python. Но для начала…

Немного терминологии

В предыдущем уроке несколько раз встречалось словосочетание "через точку". Так часто говорят для краткости. Однако для такой формы записи имён определений (module.name) существует и официальный термин: квалифицированное имя от слова "квалифицировать" ("qualify"). Соответственно, "импорт модуля целиком" (см. прошлый урок) официально называется квалифицированным импортом.

Также стоит отметить, что в Python все строчки с import принято располагать в самом начале кода модуля. Такой набор строчек часто называют "блоком импортов", хотя синтаксически этот блок никак не выделен — всего лишь обычные строчки одна за другой. Нужна эта группировка во многом для того, чтобы можно было быстро найти, что в текущем модуле откуда пришло — при работе с чужим (и даже своим!) кодом подобным часто приходится заниматься.

Импорт всего содержимого модуля

Ранее мы познакомились с модулями и рассмотрели два из трёх вариантов импортирования — импорт самого модуля и импорт отдельных определений. Рассмотрим оставшийся вариант — импортирование всего содержимого модуля. Пример:

from some_module import *
from another_module import *

Здесь из модулей some_module и another_module неявно импортируются все определения. Часто после такого импорта программисту становятся доступны десятки переменных, констант, функций и тому подобного. В этом-то и кроется проблема! Когда ниже по коду программист, читающий этот код, встречает некое имя, то ему бывает очень сложно понять, откуда это имя взялось — нельзя, просто взглянув на блок импортов, найти источник. Поиск по коду модуля тоже не помогает — все имена определений, импортированных данным способом, скрываются за *!

Большинство руководств по написанию хорошего кода на Python крайне не рекомендует использовать такой стиль импортирования. Однако в реальном коде такие импорты встречаются, поэтому мы не могли не упомянуть этот вариант.

Сочетание способов импортирования

Импортирование модуля целиком (т.е. квалифицированное) и импортирование отдельных определений могут сочетаться даже применительно к одному и тому же модулю!

Давайте рассмотрим пример.

В модуле computation.py определим функцию и переменные:

# file: computation.py
PI = 3.1415926
E = 2.7182818

def pi_times(x):
    return x * PI

А в модуле main.py сделаем разными способами импорты из модуля computation.py:

# file: main.py
import computation
from computation import PI, E
from computation import pi_times

print(PI)
print(computation.E)
print(pi_times(2))
print(computation.pi_times(E))

Из кода видно, что:

  • оба способа импорта использованы совместно,
  • импортировать отдельные определения можно в несколько заходов,
  • если модуль импортирован по имени, то "через точку" можно получить доступ и к тем определениям, которые уже явно импортированы.