Jak analyzovat argumenty příkazového řádku v Pythonu

Photo of author

By etechblogcz

Chcete-li spouštět skripty v Pythonu s využitím argumentů z příkazové řádky, je důležité umět je správně zpracovat. V tomto článku se podíváme, jak analyzovat tyto argumenty pomocí vestavěných modulů sys, getopt a argparse.

Běžně se uživatelský vstup získává pomocí funkce input(). Nicméně, pro některé aplikace je výhodnější předávat parametry přímo při spuštění skriptu z terminálu.

V následujícím textu si ukážeme, jak spustit skript Pythonu s různými možnostmi a argumenty z příkazové řádky. Naučíme se také využít vestavěné moduly Pythonu pro jejich efektivní analýzu.

Začněme!

Základy práce s sys.argv v Pythonu

Pokud máte zkušenosti s programováním v jazyce C, víte, že jedním z nejběžnějších způsobů, jak předat argumenty programu, je příkazová řádka. V C se to obvykle provádí strukturou hlavní funkce s parametry argc (počet argumentů) a argv (vektor argumentů), jak ukazuje následující kód:

#include<stdio.h>

int main(int argc, char **argv){
    //argc: počet argumentů
    //argv: vektor argumentů
    
    //zpracování argumentů

    return 0;
}

Zde argc reprezentuje celkový počet argumentů a argv je pole, které obsahuje jednotlivé argumenty.

Spouštění skriptů Pythonu s argumenty

V Pythonu můžete skript spustit z příkazové řádky pomocí příkazu python3 filename.py. K tomuto příkazu můžete připojit libovolný počet argumentů:

$ python3 filename.py arg1 arg2 ... argn

Modul sys poskytuje přímou podporu pro přístup a zpracování těchto argumentů. Konkrétně sys.argv je seznam obsahující všechny argumenty z příkazové řádky, které byly použity při spuštění skriptu.

Představme si, že spouštíme soubor main.py s několika argumenty:

$ python3 main.py hello world python script

K jednotlivým argumentům můžeme přistupovat pomocí cyklu for a funkce enumerate:

# main.py

import sys

for idx, arg in enumerate(sys.argv):
    print(f"arg{idx}: {arg}")
# Výstup
arg0: main.py
arg1: hello
arg2: world
arg3: python
arg4: script

Z výstupu je vidět, že první argument (na indexu 0) je samotný název spouštěného souboru Pythonu. Další argumenty následují od indexu 1.

Tímto způsobem lze poměrně snadno zpracovávat argumenty z příkazové řádky. Nicméně, existují i problémy, jako například:

  • Jak uživatelé poznají, jaké argumenty mají předat?
  • Jaký je význam jednotlivých argumentů?

Pro tyto situace je vhodné použít moduly getopt nebo argparse, což si ukážeme v následujících částech.

Analýza argumentů pomocí modulu getopt

Nyní se zaměříme na to, jak analyzovat argumenty příkazové řádky s využitím vestavěného modulu getopt.

Po importu modulu getopt, můžeme specifikovat argumenty, které se mají analyzovat, a to včetně krátkých a dlouhých voleb. Pro analýzu se používá část sys.argv od indexu 1, tedy sys.argv[1:].

Předpokládejme, že chceme mít možnost zadat zprávu a název souboru. Pro krátké volby použijeme m pro zprávu a f pro soubor, pro dlouhé volby message a file.

Otázkou je, jak definovat, že konkrétní volba vyžaduje argument:

  • U krátkých voleb se to provede přidáním dvojtečky (:) za název volby.
  • U dlouhých voleb se za název přidá znak rovnítka (=).

Náš kód v souboru main.py bude vypadat následovně:

# main.py

import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=','file='])

print(opts)
print(args)

Proměnná opts bude obsahovat seznam n-tic s volbami a jejich argumenty. V proměnné args pak budou zbylé poziční argumenty.

Při spuštění skriptu můžeme zadat jak krátké, tak i dlouhé volby.

Například spuštění s dlouhými volbami:

$ python3 main.py --message hello --file somefile.txt

Výsledkem je, že opts obsahuje n-tice s volbami a args je prázdný seznam, protože nebyly předány žádné další poziční argumenty.

# Výstup
[('--message', 'hello'), ('--file', 'somefile.txt')]
[]

Stejně tak můžeme použít i krátké volby:

$ python3 main.py -m hello -f somefile.txt
# Výstup
[('-m', 'hello'), ('-f', 'somefile.txt')]
[]

⚠️ Je důležité si uvědomit, že krátká volba -m se v tomto příkladu nesmí zaměňovat s příznakem příkazové řádky -m, který se používá pro spuštění modulu jako hlavního modulu.

Jak jsme zmínili, všechny poziční argumenty, které nepředcházejí volby, se shromáždí v proměnné args. Podívejme se na příklad:

$ python3 main.py -m hello -f somefile.txt another_argument

V tomto případě seznam argumentů obsahuje položku another_argument.

# Výstup
[('-m', 'hello'), ('-f', 'somefile.txt')]
['another_argument']

Seznam opts obsahuje n-tice, které můžeme iterovat a extrahovat hodnoty argumentů pro specifické volby.

Nyní si ukážeme, jak můžeme využít tyto argumenty. Otevřeme soubor v režimu zápisu a zapíšeme do něj zprávu převedenou na velká písmena:

# 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())

Nyní spustíme main.py s krátkými volbami a argumenty:

$ python3 main.py -m hello -f thisfile.txt
[('-m', 'hello'), ('-f', 'thisfile.txt')]
[]

Po spuštění se v pracovním adresáři objeví soubor thisfile.txt, který bude obsahovat text HELLO.

$ ls
main.py  thisfile.txt
$ cat thisfile.txt
HELLO

Analýza argumentů pomocí modulu argparse

Modul argparse, který je také součástí standardní knihovny Pythonu, je dalším nástrojem pro analýzu argumentů z příkazové řádky. Poskytuje navíc i funkce pro tvorbu uživatelsky přívětivého rozhraní.

Pro analýzu je nutné importovat třídu ArgumentParser. Následně vytvoříme její instanci, nazvanou například arg_parser:

from argparse import ArgumentParser

arg_parser = ArgumentParser()

Dále definujeme dva argumenty: message (zprávu) a file (název souboru).

Pro přidání argumentů použijeme metodu add_argument(). Ve volání této metody můžeme specifikovat popis argumentu pomocí parametru help.

arg_parser.add_argument('message',help='Zpráva')
arg_parser.add_argument('file',help='Název souboru')

Po vytvoření instance arg_parser a přidání argumentů můžeme získat hodnoty argumentů pomocí metody parse_args(), která se volá na objektu arg_parser.

Hodnoty argumentů se uloží do proměnné args a můžeme k nim přistupovat pomocí syntaxe args.argument_name.

Po získání argumentů, zapíšeme zprávu do souboru, s prohozenými velkými a malými písmeny (pomocí metody swapcase()).

args = arg_parser.parse_args()

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Kompletní soubor main.py vypadá takto:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('message',help='Zpráva')
arg_parser.add_argument('file',help='Název souboru')

args = arg_parser.parse_args()
print(args)

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Základy použití argumentů z příkazové řádky

Abychom pochopili, jak se používají argumenty při spuštění main.py, můžeme použít volbu --help, jak je uvedeno níže:

$ python3 main.py --help
usage: main.py [-h] message file

positional arguments:
  message     Zpráva
  file        Název souboru

optional arguments:
  -h, --help  Zobrazí tuto nápovědu a ukončí program

Z výstupu je patrné, že neexistují žádné volitelné argumenty a jak zpráva, tak soubor jsou povinné poziční argumenty. Alternativně můžete použít i krátkou volbu -h:

$ python3 main.py -h
usage: main.py [-h] message file

positional arguments:
  message     Zpráva
  file        Název souboru

optional arguments:
  -h, --help  Zobrazí tuto nápovědu a ukončí program

Oba argumenty jsou tedy poziční, a pokud je nevyplníme, dojde k chybě.

V následujícím příkladu předáme poziční argument (Ahoj) pro zprávu, ale nepředáme žádný argument pro soubor:

$ python3 main.py Ahoj
usage: main.py [-h] message file
main.py: error: the following arguments are required: file

Jakmile předáme oba poziční argumenty, můžeme vidět, že jmenný prostor args obsahuje jejich hodnoty:

$ python3 main.py Ahoj file1.txt
# Výstup
Namespace(file='file1.txt', message='Ahoj')

Po spuštění skriptu se v pracovním adresáři objeví soubor file1.txt:

$ ls
file1.txt  main.py

A jeho obsah bude řetězec Ahoj s prohozenými písmeny, tedy aHOJ:

$ cat file1.txt
aHOJ

Jak nastavit argumenty jako volitelné

Chceme-li, aby argumenty byly volitelné, musíme před název argumentu přidat --.

Upravme main.py tak, aby byly argumenty zprávy i souboru volitelné:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='Zpráva')
arg_parser.add_argument('--file',help='Název souboru')

Protože oba argumenty jsou nyní volitelné, můžeme pro ně nastavit výchozí hodnoty:

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

Kompletní main.py nyní vypadá takto:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='Zpráva')
arg_parser.add_argument('--file',help='Název souboru')

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())

Při kontrole nápovědy uvidíme, že zpráva i soubor jsou nyní volitelné, což znamená, že můžeme spustit main.py bez jakýchkoli argumentů.

$ python3 main.py --help
usage: main.py [-h] [--message MESSAGE] [--file FILE]

optional arguments:
  -h, --help         Zobrazí tuto nápovědu a ukončí program
  --message MESSAGE  Zpráva
  --file FILE        Název souboru
$ python3 main.py

Pokud nebyly zadány žádné argumenty, hodnoty souboru i zprávy budou None:

# Výstup
Namespace(file=None, message=None)

V takovém případě se použije výchozí zpráva Python3 a název souboru myfile.txt. V pracovním adresáři tak vznikne soubor myfile.txt:

$ ls
file1.txt  main.py  myfile.txt

Obsah souboru bude řetězec Python3 s prohozenými písmeny:

$ cat myfile.txt
pYTHON3

Můžeme také použít argumenty --message a --file pro lepší čitelnost příkazu:

$ python3 main.py --message Coding --file file2.txt
# Výstup
Namespace(file='file2.txt', message='Coding')

V pracovním adresáři se objeví nový soubor file2.txt:

$ ls
file1.txt  file2.txt  main.py  myfile.txt

A jeho obsahem bude text coDING:

$ cat file2.txt
cODING

Závěr

V tomto tutoriálu jsme si ukázali, jak pracovat s argumenty příkazové řádky v Pythonu. Zde je krátký souhrn klíčových bodů:

  • Stejně jako v jazyce C, i v Pythonu můžeme přistupovat k argumentům z příkazové řádky prostřednictvím seznamu sys.argv. Položka sys.argv[0] je název spouštěného skriptu, proto nás zajímá analýza argumentů od sys.argv[1:].
  • Pro lepší čitelnost a možnost definování voleb lze využít moduly getopt a argparse.
  • Modul getopt umožňuje analyzovat seznam argumentů od indexu 1. Můžeme definovat jak krátké, tak i dlouhé volby.
  • Pokud volba vyžaduje argument, přidáme za její název dvojtečku (:) u krátkých voleb a rovnítko (=) u dlouhých voleb.
  • Modul argparse nám umožňuje vytvořit instanci ArgumentParser a použít metodu add_argument() k přidávání pozičních argumentů. Pro definování volitelných argumentů se před jejich názvy v metodě add_argument() vkládá --.
  • Hodnoty argumentů lze načíst voláním metody parse_args() na instanci ArgumentParser.

V budoucnu se podíváme na další témata spojená s Pythonem, například na bezpečné hashování.