Zastanawiasz się, jak uruchamiać skrypty Pythona z parametrami przekazywanymi w linii komend? Ten artykuł wyjaśni, jak efektywnie przetwarzać argumenty wiersza poleceń, wykorzystując w tym celu moduły sys, getopt oraz argparse w języku Python.
W Pythonie, standardowo do pobierania danych od użytkownika wykorzystuje się funkcję `input()`. Niemniej jednak, w pewnych sytuacjach, potrzebne może być przekazywanie dodatkowych informacji do skryptu bezpośrednio podczas jego uruchamiania w terminalu.
W niniejszym poradniku nauczymy się, jak uruchamiać skrypty Pythona z opcjami i argumentami wprowadzonymi w linii poleceń. Następnie, zgłębimy wiedzę o tym, jak za pomocą wbudowanych modułów Pythona skutecznie analizować te opcje i argumenty.
Zacznijmy!
Zrozumienie `sys.argv` w Pythonie
Osoby z doświadczeniem w programowaniu w C wiedzą, że jednym z podstawowych sposobów przekazywania danych do programu jest linia komend. W C, można zorganizować funkcję `main` w następujący sposób:
#include<stdio.h> int main(int argc, char **argv){ //argc: licznik argumentów //argv: tablica argumentów //operacje na argumentach return 0; }
W powyższym przykładzie, `argc` przechowuje liczbę argumentów, natomiast `argv` to tablica, w której przechowywane są te argumenty.
Uruchamianie skryptów Pythona z argumentami wiersza poleceń
W Pythonie, skrypt można uruchomić za pomocą polecenia `python3 nazwa_pliku.py`. Wykonując to polecenie, możemy również przekazać dowolną liczbę dodatkowych parametrów:
$ python3 filename.py arg1 arg2 ... argn
Moduł `sys` umożliwia łatwy dostęp i przetwarzanie tych argumentów. `sys.argv` to lista wszystkich argumentów wiersza poleceń, które zostały podane przy uruchamianiu skryptu Pythona.
Oto prosty przykład, w którym uruchamiamy skrypt `main.py` z dodatkowymi parametrami:
$ python3 main.py hello world python script
Możemy iterować przez wektor argumentów za pomocą pętli `for` i funkcji `enumerate`:
# main.py import sys for idx, arg in enumerate(sys.argv): print(f"arg{idx}: {arg}")
# Wynik arg0:main.py arg1:hello arg2:world arg3:python arg4:script
Widzimy, że pierwszy argument (o indeksie 0) to nazwa samego skryptu. Kolejne argumenty są indeksowane od 1.
Jest to podstawowy, działający program, który akceptuje i przetwarza argumenty wiersza poleceń. Zauważamy jednak pewne niedociągnięcia:
- Skąd użytkownicy programu mają wiedzieć, jakie parametry należy przekazać?
- Jaki jest cel tych argumentów?
Nie jest to oczywiste. Aby rozwiązać ten problem, można skorzystać z modułów `getopt` lub `argparse`. Omówimy je w kolejnych sekcjach.✅
Analiza argumentów wiersza poleceń za pomocą `getopt`
Przeanalizujmy teraz argumenty wiersza poleceń przy użyciu wbudowanego modułu `getopt`.
Po zaimportowaniu `getopt` z modułu `getopt`, możemy zdefiniować argumenty do analizy, jak również krótkie i długie opcje. Chcemy analizować argumenty od indeksu 1 z listy `sys.argv`. Zatem, wycinek do przeanalizowania to `sys.argv[1:]`.
W naszym przykładzie będziemy potrzebować wiadomości oraz nazwy pliku. Użyjemy `m` i `f` jako opcji krótkich, a `message` i `file` jako opcji długich.
Jak określić, czy dana opcja powinna przyjmować argument?
- W opcjach krótkich, dodanie dwukropka (:) po nazwie opcji, oznacza, że opcja wymaga argumentu.
- W opcjach długich, znak równości (=) po nazwie opcji sygnalizuje, że opcja wymaga argumentu. Za pomocą tej metody, możemy przechwycić opcje oraz przypisane do nich wartości.
Po wprowadzeniu tych zmian, nasz kod w `main.py` powinien wyglądać następująco:
# main.py import sys from getopt import getopt opts, args = getopt(sys.argv[1:],'m:f:',['message=','file=']) print(opts) print(args)
Tutaj, zmienna `opts` zawiera opcje oraz ich argumenty jako listę krotek. Wszystkie inne argumenty, które nie są opcjami, są zapisane w zmiennej `args`.
Możemy teraz przekazać komunikat oraz nazwę pliku podczas uruchamiania skryptu, używając zarówno krótkich, jak i długich opcji.
Uruchamiając `main.py` z opcjami długimi, otrzymujemy:
$ python3 main.py --message hello --file somefile.txt
Opcje i ich argumenty są zapisane jako krotki w zmiennej `opts`. Ponieważ nie przekazaliśmy dodatkowych argumentów pozycyjnych, lista `args` jest pusta.
# Wynik [('--message', 'hello'), ('--file', 'somefile.txt')] []
Równoważnie, możemy również użyć opcji krótkich, jak pokazano poniżej:
$ python3 main.py -m hello -f somefile.txt
# Wynik [('-m', 'hello'), ('-f', 'somefile.txt')] []
⚠️ Opcja `-m` w tym przykładzie nie powinna być mylona z flagą wiersza poleceń `-m`, która służy do uruchamiania modułu jako głównego modułu podczas uruchamiania skryptu Pythona.
Na przykład, aby uruchomić moduł `unittest` jako główny moduł podczas uruchamiania `main.py`, użyjemy polecenia `python3 -m unittest main.py`.
Wcześniej wspominaliśmy, że wszystkie dodatkowe argumenty pozycyjne zostaną zapisane w zmiennej `args`. Oto przykład:
$ python3 main.py -m hello -f somefile.txt another_argument
W tym przypadku, lista argumentów zawiera argument pozycyjny `another_argument`.
# Wynik [('-m', 'hello'), ('-f', 'somefile.txt')] ['another_argument']
Jak widzieliśmy, `opts` to lista krotek. Możemy iterować po tej liście, rozpakowując krotki, aby uzyskać argumenty przypisane do poszczególnych opcji.
Co jednak zrobimy z nazwą pliku i komunikatem po przetworzeniu tych argumentów? Otworzymy plik w trybie zapisu i zapiszemy do niego wiadomość przekonwertowaną na wielkie litery.
# main.py import sys from getopt import getopt opts, args = getopt(sys.argv[1:],'m:f:',['message=','file=']) print(opts) print(args) for option, argument in opts: if option == "-m": message = argument if option == '-f': file = argument with open(file,'w') as f: f.write(message.upper())
Uruchommy teraz skrypt `main.py` z krótkimi opcjami oraz argumentami wiersza poleceń.
$ python main.py -m hello -f thisfile.txt [('-m', 'hello'), ('-f', 'thisfile.txt')] []
Po uruchomieniu `main.py` w bieżącym katalogu roboczym, pojawi się plik `thisfile.txt`, zawierający wiadomość „hello”, przekonwertowaną na wielkie litery („HELLO”).
$ ls main.py thisfile.txt
$ cat thisfile.txt HELLO
Jak analizować argumenty wiersza poleceń za pomocą `argparse`
Moduł `argparse`, będący częścią standardowej biblioteki Pythona, oferuje bardziej zaawansowane narzędzia do analizy argumentów wiersza poleceń, a także do tworzenia interfejsów wiersza poleceń.
Aby skorzystać z `argparse` importujemy klasę `ArgumentParser` z modułu `argparse`. Następnie, tworzymy instancję `arg_parser` – obiekt klasy `ArgumentParser`:
from argparse import ArgumentParser arg_parser = ArgumentParser()
Teraz, dodajmy dwa argumenty wiersza poleceń:
- `message`: ciąg znaków reprezentujący wiadomość oraz
- `file`: nazwa pliku, z którym chcemy pracować.
W tym celu użyjemy metody `add_argument()` na obiekcie `arg_parser`. W wywołaniu metody możemy również dodać opis argumentu za pomocą parametru `help`.
arg_parser.add_argument('message',help='ciąg znaków wiadomości') arg_parser.add_argument('file',help='nazwa pliku')
Do tej pory utworzyliśmy instancję `arg_parser` i dodaliśmy argumenty. Gdy program jest uruchamiany, możemy użyć metody `parse_args()` na obiekcie `arg_parser`, aby otrzymać wartości argumentów.
W tym przykładzie, wartości argumentów są zapisane w zmiennej `args`. Możemy użyć `args.argument_name`, aby uzyskać wartości poszczególnych argumentów.
Po pobraniu wartości argumentów, zapiszemy wiadomość z odwróconą wielkością liter (metodą `swapcase()`) do pliku.
args = arg_parser.parse_args() message = args.message file = args.file with open(file,'w') as f: f.write(message.swapcase())
Łącząc wszystkie elementy, nasz plik `main.py` będzie wyglądać następująco:
# main.py from argparse import ArgumentParser arg_parser = ArgumentParser() arg_parser.add_argument('message',help='ciąg znaków wiadomości') arg_parser.add_argument('file',help='nazwa pliku') args = arg_parser.parse_args() print(args) message = args.message file = args.file with open(file,'w') as f: f.write(message.swapcase())
Zrozumienie użycia argumentów wiersza poleceń
Aby dowiedzieć się, jak używać argumentów podczas uruchamiania skryptu `main.py`, skorzystajmy z opcji `–help`:
$ python3 main.py --help usage: main.py [-h] message file positional arguments: message ciąg znaków wiadomości file nazwa pliku optional arguments: -h, --help show this help message and exit
W tym przypadku nie mamy żadnych argumentów opcjonalnych. Zarówno `message`, jak i `file` są argumentami pozycyjnymi, a więc są wymagane. Możemy również użyć opcji `-h`:
$ python3 main.py -h usage: main.py [-h] message file positional arguments: message ciąg znaków wiadomości file nazwa pliku optional arguments: -h, --help show this help message and exit
Jak widzimy, oba argumenty są domyślnie argumentami pozycyjnymi. Jeżeli nie przekażemy jednego lub więcej z nich, wystąpi błąd.
W poniższym przykładzie, podaliśmy argument pozycyjny (`Hello`) dla wiadomości, ale nie podaliśmy żadnej wartości dla argumentu plik.
W rezultacie otrzymujemy informację o tym, że argument pliku jest wymagany.
$ python3 main.py Hello usage: main.py [-h] message file main.py: error: the following arguments are required: file
Kiedy uruchomimy `main.py`, przekazując oba argumenty pozycyjne, zauważymy, że przestrzeń nazw `args` zawiera wartości argumentów.
$ python3 main.py Hello file1.txt
# Wynik Namespace(file="file1.txt", message="Hello")
Sprawdzając zawartość bieżącego katalogu roboczego, zobaczymy, że skrypt utworzył plik `file1.txt`:
$ ls file1.txt main.py
Oryginalny ciąg znaków to „Hello”. Po zamianie wielkości liter, w pliku `file1.txt` zapisana jest wartość „hELLO”.
$ cat file1.txt hELLO
Jak sprawić, by argumenty wiersza poleceń były opcjonalne
Aby uczynić argumenty wiersza poleceń opcjonalnymi, należy poprzedzić nazwę argumentu znakiem `–`.
Zmodyfikujmy `main.py` w taki sposób, aby zarówno argumenty `message`, jak i `file` były opcjonalne.
# main.py from argparse import ArgumentParser arg_parser = ArgumentParser() arg_parser.add_argument('--message',help='ciąg znaków wiadomości') arg_parser.add_argument('--file',help='nazwa pliku')
Ponieważ oba argumenty wiersza poleceń są opcjonalne, możemy ustawić dla nich wartości domyślne.
if args.message and args.file: message = args.message file = args.file else: message="Python3" file="myfile.txt"
W tym momencie nasz plik `main.py` zawiera następujący kod:
# main.py from argparse import ArgumentParser arg_parser = ArgumentParser() arg_parser.add_argument('--message',help='ciąg znaków wiadomości') arg_parser.add_argument('--file',help='nazwa pliku') args = arg_parser.parse_args() print(args) if args.message and args.file: message = args.message file = args.file else: message="Python3" file="myfile.txt" with open(file,'w') as f: f.write(message.swapcase())
Sprawdzając użycie, zobaczymy, że zarówno `message`, jak i `file` są argumentami opcjonalnymi. Oznacza to, że możemy uruchomić `main.py` bez przekazywania żadnych argumentów.
$ python3 main.py --help usage: main.py [-h] [--message MESSAGE] [--file FILE] optional arguments: -h, --help show this help message and exit --message MESSAGE ciąg znaków wiadomości --file FILE nazwa pliku
$ python3 main.py
W przestrzeni nazw argumentów, zarówno `file`, jak i `message`, mają wartość `None`.
# Wynik Namespace(file=None, message=None)
W tym przypadku, używane są domyślne wartości: nazwa pliku `myfile.txt` oraz komunikat `Python3`. Plik `myfile.txt` znajduje się teraz w katalogu roboczym:
$ ls file1.txt main.py myfile.txt
Zawiera on ciąg „Python3” z zamienionymi wielkościami liter:
$ cat myfile.txt pYTHON3
Możemy również użyć zarówno argumentów `–message`, jak i `–file`, co czyni polecenie bardziej czytelnym.
$ python3 main.py --message Coding --file file2.txt
# Wynik Namespace(file="file2.txt", message="Coding")
Plik `file2.txt` pojawił się w katalogu roboczym:
$ ls file1.txt file2.txt main.py myfile.txt
Zgodnie z oczekiwaniami, zawiera ciąg „cODING”.
$ cat file2.txt cODING
Podsumowanie
Podsumowując, w tym artykule nauczyliśmy się:
- Podobnie jak w języku C, w Pythonie dostęp do argumentów wiersza poleceń uzyskujemy poprzez iterację po wektorze `sys.argv`. `sys.argv[0]` to nazwa skryptu. Nas interesują argumenty od `sys.argv[1:]`.
- Aby poprawić czytelność i mieć możliwość dodawania opcji, można użyć modułów `getopt` i `argparse`.
- Moduł `getopt` służy do analizy listy argumentów, zaczynając od indeksu 1 aż do końca listy. Możemy definiować zarówno krótkie, jak i długie opcje.
- Gdy opcja przyjmuje argument, należy dodać dwukropek (:) lub znak równości (=) po nazwie opcji (odpowiednio dla krótkiej i długiej opcji).
- Moduł `argparse` umożliwia tworzenie instancji obiektu `ArgumentParser` oraz dodawanie wymaganych argumentów pozycyjnych za pomocą metody `add_argument()`. Użycie znaku `–` przed nazwą argumentu sprawia, że argument staje się opcjonalny.
- Aby pobrać wartości argumentów, wywołujemy metodę `parse_args()` na obiekcie `ArgumentParser`.
Następnie, dowiedz się, jak wykonywać bezpieczne mieszanie w Pythonie.
newsblog.pl