Dawid Loranc „What I cannot create, I do not understand.” - Richard Feynman
Argumenty w linii komend w Pythonie

Argumenty w linii komend w Pythonie

09.04.2017

Zastanawiałem się ostatnio jak zrealizować w Pythonie obsługę argumentów przekazywanych do skryptu z poziomu linii komend. Można zrobić to bardzo prosto używając sys.argv ze biblioteki standardowej:

import sys

if __name__ == '__main__':
    print "\n".join(sys.argv)

Powyższy przykład wyświetla argumenty jeden pod drugim. Wyrażenie warunkowe if __name__ == '__main__': sprawdza czy skrypt został wywołany w konsoli. Jeśli skrypt został zaimportowany w innym pliku, to wtedy kod się nie wykona.

sys.argv

docopt - czyli zaprzęgamy docstringi do pracy

sys.argv nie pozwala jednak na wiele. Trzeba samemu zadbać o poprawną obsługę argumentów, a jeśli chcemy mieć pomoc (przy wywołaniu skryptu z --help) do naszego skryptu, to musimy pamiętać o jej zgodności z resztą kodu. Do prostych rzeczy sys.argv jednak wystarczy. Jeśli jednak chcemy zbudować narzędzie, które będzie intensywnie wykorzystywane w miejscu, które programiści lubią najbardziej (czyli w konsoli), to musimy skorzystać z czegoś innego. Dość popularnym rozwiązaniem jest argparse. Ja skorzystałem jednak z narzędzia docopt, które wydaje mi się dość interesujące, gdyż argumenty buduje się za pomocą docstringa. Fajna sprawa.

Zaczynamy od instalacji narzędzia:

pip install docopt

Napiszmy coś prostego, niech będzie to skrypt sumujący liczby. Na razie jednak nie sumujemy, zobaczymy z czym mamy do czynienia.

"""Sum integer values.

Usage:
  sum.py <numbers>...
  sum.py (-h | --help)
  sum.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Sum 1.0')

    numbers = arguments['<numbers>']

    try:
        numbers = list(map(int, numbers))
        print(sum(numbers))
    except ValueError:
        print('Cannot cast value(s) to integer.')

Z zawartości docstringa łatwo się domyślić co wywołać i z jakimi argumentami mamy do czynienia. Nawiasy trójkątne oznaczają argumenty, myślniki (dwa lub jeden) to opcje, a trzy kropki oznaczają to, że argumenty mogą się powtarzać. Nawiasy w połączeniu z pionową kreską natomiast oznaczają wzajemnie wykluczające się opcje.

Czas na testy, wowołajmy --version i --help:

python sum.py --version

python sum.py --help

Sprawdźmy co się stanie jak wywołamy z argumentami 1 2 3 4:

python sum.py 1 2 3 4

Widzimy, że zawartością zmiennej arguments jest słownik zawierający trzy pola --help, --version i <numbers>.

Dobra, zmodyfikujmy trochę kod, tym razem zsumujmy te liczby.

if __name__ == '__main__':
    arguments = docopt(__doc__, version='Sum 1.0')

    numbers = arguments['<numbers>']

    # trzeba zrzutować na inty bo mamy do czynienia z listą w postaci ['1', '2', '3', '4']
    numbers = list(map(int, numbers))

    print(sum(numbers))

Wyświetli się:

python sum.py 1 2 3 4

Jak widać, biblioteka docopt jest bardzo prosta w użyciu. Nie trzeba się bawić w grzebanie w dokumentacji jak w przypadku argparse i tym podobnych bibliotek.

Więcej szczegółów na temat docopt można znaleźć na stronie http://docopt.org/.

Udostępnij: