sys.argv Python
| Введение | |
| sys.argv[0] | |
| Необязательный аргумент | |
| Неизвестное число аргументов | |
| Пример | |
| Приём для импорт в REPL | |
| В других языках | |
| Похожие статьи |
Введение
Это статья про агрументы, которые передаются в скрипт извне. Например, из терминала.
Передача аргументов в скрипт это распространённая практика для CI/CD.
Про обычные аргументы, то есть такие, которые передаются в функцию внутри модуля, читайте статью
*args, **kwargs
Чтобы передать аргументы в Python скрипт из командной строки нужно воспользоваться библиотекой sys
import sys
Далее каждый аргумент нужно принимать с помощью sys.argv
a = sys.argv[0] b = sys.argv[1] c = sys.argv[2] …
sys.argv[0]
Нулевой элемент это название самого скрипта.
# zero.py import sys print(f"First argument argv[0] is {sys.argv[0]}")
python zero.py
Можно передать ещё какие-то аргументы, ошибки не будет.
python zero.py argument
First argument argv[0] is .\zero.py
В Linux
python3 zero.py
First argument argv[0] is zero.py
sys.argv[1]
Первый элемент это первый переданный аргумент.
# one.py import sys print(f"Second argument argv[1] is {sys.argv[1]}")
Такой скрипт нельзя вызвать без аргументов.
python .\one.py
Traceback (most recent call last): File "C:\python\one.py", line 4, in <module> print(f"Second argument argv[1] is {sys.argv[1]}") ~~~~~~~~^^^ IndexError: list index out of range
python .\one.py Test
Second argument argv[1] is Test
О том как сделать скрипт устойчивым к непередаче аргумента читайте в следующей главе.
Необязательный аргумент
Если нужно сохранить возможность не передавать никаких аргументов - можно добавить проверку длинны sys.argv
# one.py import sys if len(sys.argv) > 1: a = sys.argv[1] else: a = None print(f"Second argument argv[1] is {a}")
python .\one.py
Second argument argv[1] is None
python .\one.py Test
Second argument argv[1] is Test
Можно задать строгое условие на количество аргментов:
import sys if len(sys.argv) == 2: a = sys.argv[1] else: a = "default" print("a =", a) print(type(a))
python sysargs.py 2
a = 2 <class 'str'>
python sysargs.py
a = default <class 'str'>
Неизвестное заранее количество аргументов
Что делать если число аргументов заранее неизвестно.
Используем следующее свойство
списков
в Python
lst = ["a", "b", "c"] print(lst[1:])
['b', 'c']
import sys print(f"Script received positional args: {sys.argv[1:]}")
python positional.py arg1 arg2 'arg as phrase'
Script received positional args: ['arg1', 'arg2', 'arg as phrase']
Обратите внимание, на возможность передавать с помощью кавычек аргументы с пробелами.
Пример
Скрипт
add.py,
который складывает две строки.
Без проверки на существование аргумента.
# one.py import sys first = sys.argv[1] second = sys.argv[2] print(f"{first} + {second} = {first + second}")
python add.py topbicycle .ru
topbicycle + .ru = topbicycle.ru
В такой скрипт можно передать ровно два аргумента.
Рассмотрим похожий скрипт, успешно принимающий разное количество аргументов.
import sys st = "" for el in sys.argv[1:]: st += el print(st)
В этот скрипт можно передавать разное количество аргументов
python unknown_len.py
python unknown_len.py 1 2
12
python unknown_len.py 1 2 3 a b cde 4 5 None
123abcde45None
Чтобы проделать похожие действия с целыми числами - используем функцию int() так как даже если передать числа, они будут получены как строки.
import sys first = int(sys.argv[1]) second = int(sys.argv[2]) print(f"{first} + {second} = {first + second}")
python add.py 3 4
3 + 4 = 7
Теперь то же самое но для заранее неизвестного числа элементов. Некоторые элементы могут быть неприводимы к типу int.
Для разнообразия используем range(1, len(sys.argv)) вместо sys.argv[1:]
import sys s = 0 x = 0 for i in range(1, len(sys.argv)): try: x = int(sys.argv[i]) except ValueError: x = 0 finally: s += x print(s)
python unknown_len.py 1 2 3 4 5
15
Можно передать в скрипт и нечисловые аргументы
python unknown_len.py 1 2 3 a b cde 4 5 None
15
Можно ничего не передавать, ошибки не будет. Сумма будет равна нулю.
python unknown_len.py
0
Пример 2
Рассмотрим скрипт words.py из курса от Pluralsight
import sys from urllib.request import urlopen def fetch_words(url): # story = urlopen("https://testsetup.ru/testdata/words_en.txt") story = urlopen(url) story_words = [] for line in story: line_words = line.decode("utf8").split() for word in line_words: story_words.append(word) story.close() return story_words def print_words(story_words): for word in story_words: print(word) def main(): url = sys.argv[1] words = fetch_words(url) print_words(words) if __name__ == "__main__": main()
Этот скрипт не будет работать если не передать нужный url через терминал
python words.py "https://testsetup.ru/testdata/words_en.txt"
Желательно также предусмотреть вызов функции main() после импорта.
В текущем виде будут проблемы
python
Python 3.9.5 (default, Jun 15 2021, 15:30:04) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information.
>>> from words import *
>>> main()
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/andrei/python/words.py", line 23, in main url = sys.argv[1] IndexError: list index out of range
>>> main("https://testsetup.ru/testdata/words_en.txt")
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: main() takes 0 positional arguments but 1 was given
Решается проблема добавлением sys.argv[1] в вызов main
def main(url): words = fetch_words(url) print_words(words) if __name__ == "__main__": main(sys.argv[1])
>>> main("https://testsetup.ru/testdata/words_en.txt")
В других языках
В
C
аналогичную функцию выполняет
int argc, char* argv[]
В
Bash
это
встроено по умолчанию
.
Автор статьи: Андрей Олегович
| Command Line Interface | |
| argparse |