Argumenty w linii komend w Pythonie
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.
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, wywołajmy --version
i --help
:
Sprawdźmy co się stanie jak wywołamy z argumentami 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ę:
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/.