скрипт (англ. script) — так часто называют программы на интерпретируемых языках, представляющие из себя простые последовательности команд, которые компьютеру нужно выполнить. Часто языки, которые максимально упрощают написание скриптов и их запуск, называют "скриптовыми языками" или же "языками для написания сценариев"
Python отличный скриптовый язык:
последовательность команд в простых сценариях
не нужно никак оформлять и запускать скрипты максимально
просто — мы просто пишем команды одну за другой в файл:
# file <script.py>
print('Hello, world!')
print('This is a python-script!')
а затем просто вызываем интерпретатор с полученным файлом на входе:
$ python3 script.py Hello, world! This is a python-script!
Написание скриптов — отличная отправная точка для тех, кто только начинает знакомиться с программированием!
В unix-подобных операционных системах (macOS, Linux, BSD etc)
командные оболочки умеют запускать скрипты на любых языках,
в т.ч. и на Python, если эти скрипты
сообщают оболочке, какой интерпретатор нужно вызывать
для выполнения сценария. Интерпретатор указывается
специальной строкой в самой первой строчке файла скрипта,
которая называется shebang, от названий
первых двух символов такой строчки:
# называется "sharp",
а ! - "bang!".
Типичный shebang выглядит так:
#!/usr/bin/python3
где после символов #! идёт путь до интерпретатора. Командная оболочка при запуске скрипта, содержащего shebang, читает первую строку и пробует запустить указанный интерпретатор. Если скрипту с указанным shebang дать права на исполнение, то интерпретатор в командной строке можно будет не указывать:
$ cat script.py
#!/usr/bin/python3
print('Hello!')
$ chmod +x script.py
$ ./script.py
Hello!
В работе програмист может использовать разные версии Python,
да и путь к интерпретатору будет отличаться от /usr/bin
в виртуальных окружениях!
В этом случае чтобы скрипт запускался всегда с нужной версией Python
нужно всего лишь не указывать путь до команды python напрямую,
а использовать программу env.
Эта программа умеет находить и запускать программы с учётом
переменных окружения
и, т.к. при активации виртуального окружения модифицируется
переменная $PATH,
то env будет запускать именно ту версию интерпретатора,
которая нам нужна (она просто найдётся раньше, т.к. путь до исполняемых файлов окружения добавляется в начало $PATH).
самый правильный способ указывать shebang в проектах на python:
#!/usr/bin/env python3
print('Hello!')
Путь до env всегда располагается именно в /usr/bin/
и не встречается в нескольких версиях.
Давайте смоделируем некий исходный скрипт:
# file <first_script.py>
def greet(who):
print('Hello, {}!'.format(who))
greet('Вова')
greet('Алла')
Далее — новый скрипт, в котором мы
хотим переиспользовать функцию greet из первого модуля
(скрипты — тоже модули):
# file <second_script.py>
from first_script import greet
greet('Витя')
Запустим первый скрипт, а затем — второй (оба файла расположены в текущей директории):
$ python3 first_script.py
Hello, Вова!
Hello, Алла!
$ python3 second_script.py
Hello, Вова!
Hello, Алла!
Hello, Витя!
Мы видим, что при выполнении второго скрипта выполнился и первый, хотя мы всего лишь импортировали из него одну функцию! Поскольку файл первого скрипта содержит не только определения, но и непосредственные действия (statements), то при загрузке файла эти действия будут выполнены.
Выходит, нам нужно как-то различать ситуации когда
Для этого нам понадобится специальная переменная
__name__
Машинерия импортирования при загрузке модуля в первый раз
(первый для текущего запуска интерпретатора) добавляет в этот модуль
несколько переменных специального вида.
Этих переменных довольно много, но нам пока интересна одна —
переменная __name__.
такие имена часто встречаются в Python-коде и как правило имеют какой-то специальный смысл.
Что же хранит переменная __name__ в каждом конкретном случае?
'__main__'.Глядя на значение этой переменной, можем отличать "запуск" от импортирования.
перепишем наш примерfirst_script.py с применением этой переменной:
# file <first_script.py>
def greet(who):
print('Hello, {}!'.format(who))
if __name__ == '__main__':
greet('Вова')
greet('Алла')
main
В теле условия if __name__… у нас перечислен
набор действий, которые выполняются
при запуске скрипта. Со временем таких действий может стать
достаточно много. Поэтому существует соглашение:
в теле условия if __name__… делают всего один
вызов функции без аргументов main,
которую объявляют выше в этом же модуле
(само условие принято располагать в самом конце модуля скрипта).
С учётом всех описанных рекомендаций финальная версия скрипта first_script.py
будет выглядеть так:
#!/usr/bin/env python3 def greet(who): print('Hello, {}!'.format(who)) def main(): greet('Вова') greet('Алла') if __name__ == '__main__': main()
Такой скрипт можно
main;Рассмотрим немного экзотический, но всё же встречающийся случай — запуск пакета. Могло бы показаться, что раз при загрузке пакета всегда загружается модуль __init__.py, то и функцию main, и условие нужно располагать в нём. Но авторы по ряду причин решили реализовать запуск пакетов несколько иначе: при загрузке пакета пред запуском ищется модуль __main__.py и выполняется, как скрипт. Здесь мы не будем углубляться в причины, побудившие авторов языка сделать именно так, и просто запомним, что исполняемые пакеты всегда содержат скрипт __main__.py.
Когда же может понадобится запуск пакета? Сходу можно представить такой пример. Пусть мы имели один небольшой скрипт. Со временем кода в нём становилось всё больше — настолько много, что этот скрипт стало совершенно невозможно поддерживать. Мы решили превратить один модуль в пакет, содержащий несколько. Но как такой пакет в дальнейшем запускать? Вот для этого мы и можем использовать модуль __main__.py!