Модули в Python

Пока каждая ваша программа помещалась в один файл, и этого хватало. Но однажды вы напишете функцию, которая пригодится и в следующей задаче, а перенести её туда получится только копированием. Скопировали в три скрипта, нашли ошибку — правите в трёх местах.

Значит, нужен способ держать код в отдельном файле и подключать оттуда только нужное. Такой файл называется модулем.

Вы уже пользуетесь модулями

Строка import math встречалась вам в главах про библиотеки. Посмотрим внимательнее, что происходит после неё.

Python 3.13
import math

print(math.sqrt(144))
12.0
print(type(math))
<class 'module'>

import не вставляет текст чужого файла в ваш. Он создаёт объект-модуль и кладёт его в переменную с именем math. Дальше math.sqrt — обычное обращение к атрибуту объекта, точно такое же, как "строка".upper().

Создаём свой модуль

Теперь сделаем такой файл сами. Пусть у нас есть небольшой скрипт, который считает цены: прибавляет НДС и применяет скидки. Сам расчёт положим в prices.py, а в main.py оставим только вывод результатов:

main.py
1import prices2 3print(prices.with_vat(100))  # 120.04print(prices.discount(1000, 15))  # 850.05print(prices.VAT)  # 0.26 

main.py пишет import prices, и Python находит prices.py в той же папке. Имя модуля берётся из имени файла: убираем .py, получаем prices. Этого достаточно, чтобы импорт заработал.

Раз имя модуля — это имя файла, называйте файлы в snake_case: user_interface.py, а не UserInterface.py. И не random.py: файл, названный как модуль стандартной библиотеки, перекроет настоящий модуль.

Код модуля выполняется ровно один раз

При импорте Python выполняет файл сверху донизу. В boot.py ниже print стоит на верхнем уровне, не внутри функции, поэтому сработает при импорте. Импортируем этот модуль двумя строками подряд:

main.py
1import boot2import boot3 4print("а строк с import было две")5 
boot.py выполняется
а строк с import было две

Хотя строк с import было две, файл выполнился один раз: готовые модули Python запоминает и при повторном импорте отдаёт тот же объект. Отсюда практический вывод: на верхнем уровне модуля держат определения, а не действия — всё, что там написано, выполнится при первом же импорте, даже если ни одна функция оттуда не понадобится.

from ... import: имя переезжает к вам

Писать prices. перед каждым вызовом надоедает. Форма from ... import забирает из модуля конкретное имя и кладёт его прямо в вашу программу. В примере ниже обе формы импорта стоят рядом нарочно, чтобы в последней строке сравнить результат — в обычном коде так не пишут.

main.py
1import prices2from prices import with_vat3 4print(with_vat(100))  # 120.05print(with_vat is prices.with_vat)  # True6 

Последняя строка — самое важное здесь. Никакой копии функции не появилось: with_vat и prices.with_vat — два имени одного объекта. from ... import не «другой способ импорта», а дополнительное действие: сначала модуль импортируется целиком (со всем своим кодом), потом одно из его имён копируется в ваше пространство имён.

Итого у вас три формы, и выбирают между ними так:

  • Функций из модуля нужно много, или важно видеть, откуда взялось имя — оставьте префикс:

    Python 3.13
    import prices
    
    print(prices.with_vat(100))
  • Нужны две-три функции и вызываются они часто — заберите их по именам, код станет короче:

    Python 3.13
    from prices import with_vat, discount
    
    print(with_vat(100))
  • Имя модуля длинное или уже занято вашей переменной — подключите его под коротким именем:

    Python 3.13
    import prices as p
    
    print(p.with_vat(100))

Последняя форма — та самая причина, по которой пишут import pandas as pd.

Как отличить запуск от импорта

Как мы видели, при импорте выполняется весь код модуля. Значит, код внутри prices.py отработает в обоих случаях:

python prices.py   # запускаем сам модуль
python main.py     # запускаем программу, которая его импортирует

Но иногда код нужен только при прямом запуске файла. Например, проверка «а верно ли считают функции»: автору она удобна, а тому, кто импортирует модуль, только мешает.

Отличить одно от другого позволяет переменная __name__, она есть у каждого модуля. При импорте в ней лежит имя модуля, здесь это "prices". А у файла, который запустили напрямую, там всегда "__main__". Поэтому такое условие истинно только при прямом запуске:

Python 3.13
if __name__ == "__main__":
    print("проверка:", with_vat(100))

В prices.py ниже эта проверка стоит в самом конце, а main.py на соседней вкладке просто импортирует модуль:

prices.py
1"""Расчёт цен: НДС и скидки."""2 3VAT = 0.24 5 6def with_vat(price):7  """Цена с НДС."""8  return round(price * (1 + VAT), 2)9 10 11def discount(price, percent):12  """Цена после скидки в процентах."""13  return round(price * (1 - percent / 100), 2)14 15 16if __name__ == "__main__":17  print("проверка:", with_vat(100))18 
итог: 120.0

Запустили main.py — в выводе только его собственная строка: __name__ внутри prices.py равен "prices", условие ложно, проверка промолчала. А при прямом запуске модуля напечаталось бы проверка: 120.0.

Так один файл совмещает две роли: набор функций для чужого кода и самостоятельная программа. В этот блок кладут всё, что не должно случаться при импорте: запуск программы, разбор аргументов командной строки, проверки вроде нашей.