Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Запускаемые модули и пакеты Python: Настройка окружения

Представим, что у нас есть файл с кодом, который мы запускаем как скрипт. Файл разрастается, в нем появляются функции и прочие определения. В какой-то момент мы понимаем, что хотим переиспользовать функцию из этого модуля в другом модуле. Значит, нужно импортировать. В этом уроке мы разберемся, как работает импорт скриптов.

Импортирование скриптов

Смоделируем описанную выше ситуацию. Так будет выглядеть исходный скрипт:

# file <first_script.py>

def greet(who):
    print(f'Hello, {who}!')

greet('Bob')
greet('Ann')

Теперь посмотрим на новый скрипт, в котором мы хотим переиспользовать функцию greet из первого скрипта:

# file <second_script.py>

from first_script import greet

greet('Thomas')

Запустим первый скрипт, а затем — второй. Оба файла расположены в текущей директории:

python3 first_script.py

Hello, Bob!
Hello, Ann!

python3 second_script.py

Hello, Bob!
Hello, Ann!
Hello, Thomas!

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

Файл первого скрипта содержит определения и непосредственные действия, поэтому при загрузке файла при импорте модуля эти действия будут выполнены.

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

Выходит, нам нужно как-то различать ситуации двух типов:

  1. Модуль работает как скрипт — выполняем побочные действия
  2. Модуль или его содержимое импортируются — не выполняем побочные действия

Специальная переменная __name__

Рассмотрим механизм импорта при загрузке модуля в первый раз — а именно первый для текущего запуска интерпретатора.

Во время первой загрузки интерпретатор добавляет в модуль несколько переменных специального вида. Этих переменных довольно много, но нам пока интересна одна — переменная __name__.

Кажется, что у переменной необычное имя — в нем целых четыре символа подчеркивания. На самом деле такие имена часто встречаются в Python-коде и как правило имеют какой-то специальный смысл. Опытный разработчик обычно помнит наизусть пару десятков таких переменных, поэтому про эти переменные любят спрашивать на собеседованиях.

Посмотрим, что хранит переменная __name__ в каждом конкретном случае:

  • Если происходит обычный импорт, то эта переменная содержит полное имя модуля
  • Если происходит запуск в качестве скрипта, то переменная получает специальное значение — строку '__main__'

Глядя на значение этой переменной, мы можем отличать запуск в качестве скрипта от импортирования.

Слово main используется во многих языках для именования функции, которая вызывается автоматически при старте программы. Потому и в Python это слово используется в похожем смысле.

Давайте вернемся к нашему примеру и перепишем first_script.py с применением этого нового знания:

# file <first_script.py>

def greet(who):
    print(f'Hello, {who}!')

if __name__ == '__main__':
    greet('Bob')
    greet('Ann')

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

Функция main

Наш скрипт first_script.py уже достаточно хорош, но можно немного его улучшить.

В теле условия if __name__… перечислен набор действий, которые выполняются при запуске скрипта. Со временем таких действий может стать достаточно много.

Нередко происходят ситуации, когда нужно переиспользовать этот кусок кода. Поэтому существует соглашение: в теле условия if __name__… делают всего один вызов функции main без аргументов. Эту функцию объявляют выше в этом же модуле. При этом само условие принято располагать в самом конце модуля скрипта.

С учетом всех описанных рекомендаций финальная версия скрипта first_script.py будет выглядеть так:

#!/usr/bin/env python3

def greet(who):
    print(f'Hello, {who}!')

def main():
    greet('Bob')
    greet('Ann')

if __name__ == '__main__':
    main()

Такой скрипт можно:

  • Запускать непосредственно
  • Запускать из других скриптов, вызывая функцию main
  • Использовать как библиотеку

Запускаемые пакеты

Рассмотрим немного необычный, но все же встречающийся случай — запуск пакета.

Может показаться, что раз при загрузке пакета всегда загружается модуль __init__.py, то функцию main и условие нужно располагать в нем.

Но запуск пакетов реализован несколько иначе: при загрузке пакета интерпретатор ищет __main__.py и выполняет его как скрипт. Здесь мы не будем углубляться в причины — просто запомним, что исполняемые пакеты всегда содержат скрипт __main__.py.

Когда может понадобиться запуск пакета? Возьмем для примера один небольшой скрипт. Со временем кода в нем становилось все больше — настолько много, что этот скрипт стало совершенно невозможно поддерживать.

Представим, что мы решили превратить один модуль в пакет, содержащий модули. Но как такой пакет в дальнейшем запускать? Как раз в этом нам поможет модуль __main__.py.


Самостоятельная работа

  1. Создайте модуль module.py следующего вида:

    print(f"__name__ == '{__name__}'")
    
  2. В REPL импортируйте модуль. Запускайте интерпретатор, находясь в директории с модулем. В приглашении выполните import module

  3. Посмотрите, что выведется на экран

  4. Запустите модуль на исполнение. Для этого вызовите python3 module.py из директории, в которой вы создали модуль

  5. Посмотрите, что выводится на экран на этот раз


Дополнительные материалы

  1. Полный список того, что добавляет в модуль машинерия импортирования
  2. Имя '__main__' и его значение

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 28 ноября
профессия
от 24 542 ₸ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 28 ноября

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»