Starting with Python version 2.7, the argparse library was included in the set of standard libraries for processing arguments (parameters, keys) of the command line. I would like to stop your attention on it.
To begin, consider what interesting argparse offers.
Argparse is an elegant tool for:
- argument analysis sys.argv;
- converting string arguments into objects of your program and working with them;
- formatting and displaying informative prompts;
- much more.
One of the arguments of opponents of including argparse in Python was the argument that the standard modules already contain two libraries for semantic processing (parsing) of command line parameters. However, as the argparse developers claim, the getopt and optparse libraries are inferior to argparse for several reasons:
- Possessing the full range of actions with the usual command line parameters, they are not able to handle positional arguments. Positional arguments are arguments that affect the operation of the program, depending on the order in which they are passed to this program. The simplest example is the cp program, which has at least 2 such arguments ("cp source destination") .
- argparse produces better hint messages at the output with minimal costs (in this respect, some code redundancy can often be observed when working with optparse);
- argparse allows the programmer to set for himself which characters are parameters and which are not. In contrast, optparse considers options with syntax like "-pf, -file, + rgb, / f, etc." internally inconsistent "and" not supported by optpars and never will be ";
- argparse will give you the ability to use multiple variable values with one command line argument (nargs);
- argparse supports subcommands. This is when the main parser sends to another (subparser), depending on the input arguments.
')
To start working with argparse you need to set the parser:
ap.py: import argparse parser = argparse.ArgumentParser(description='Great Description To Be Here')
Further, the parser should indicate which objects you expect from it. In the particular case, it might look like this:
parser.add_argument('-n', action='store', dest='n', help='Simple value')
If the action (action) for this argument is not specified, then by default it will be stored (store) in the namespace, and we can also specify the type of this argument (int, boolean, etc.). If the name of the returned argument (dest) is specified, its value will be stored in the corresponding attribute namespace.
In our case:
print parser.parse_args(['-n', '3']) Namespace(n='3') print parser.parse_args([]) Namespace(n=None) print parser.parse_args(['-a', '3']) error: unrecognized arguments: -a 3
A simple example of a program that squares up the value of a positional argument (square) and forms an output depending on the optional argument (-v):
import argparse parser = argparse.ArgumentParser() parser.add_argument("square", type=int, help="display a square of a given number") parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity") args = parser.parse_args() answer = args.square**2 if args.verbose: print("the square of {} equals {}".format(args.square, answer)) else: print(answer)
Let's stop on actions (
actions ). They may be as follows:
- store: returns the value to the namespace (after an optional type cast). As already mentioned, store is the default action;
- store_const: mainly used for flags. Either return the value specified in const to you, or (if nothing is specified), None. Example:
parser.add_argument('--LifetheUniverseandEverything', action='store_const', const=42) print parser.parse_args(['--LifetheUniverseandEverything']) Namespace(LifetheUniverseandEverything=42)
- store_true / store_false: analogue of store_const, but for Boolean True and False;
- append: returns a list by adding the values of the argument elements to it. Example:
parser.add_argument('--l', action='append') print parser.parse_args('--la --lb --l Y'.split()) Namespace(l=['abY'])
- append_const: returns the value defined in the argument specification to the list. Until I had a case in which append_const would be needed.
- count: as the name implies, it counts how many times the value of this argument occurs. Example:
parser.add_argument('--verbose', '-v', action='count') print parser.parse_args('-vvv'.split()) Namespace(verbose=3)
Depending on the add_help (boolean type) argument passed to the constructor of the parser, it will be determined whether or not to include in the standard output using the keys ['-h', '--help'] help messages. The same will take place with the argument version (string type), the default keys: ['-v', '--version']. When requesting help or a version number, further execution is interrupted.
parser = argparse.ArgumentParser(add_help=True, version='4.0')
Sometimes it is necessary to define a certain set of command line parameters that will be distributed to all parsers of your program. In this case, often give an example of the need for authorization:
parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('--user', action="store") parent_parser.add_argument('--password', action="store") child_parser = argparse.ArgumentParser(parents=[parent_parser]) child_parser.add_argument('--show_all', action="store_true") print child_parser.parse_args(['--user', 'guest']) Namespace(password=None, show_all=False, user='guest')
Notice that the parent parser is created with the add_help = False parameter. This is done because each parser will honestly try to add its own '-h' key handler, which will cause a conflict situation. This raises the question of what to do if your child parser has the same keys as the parent and you want to use them without any conflicts? This is done by simply adding a conflict_handler argument:
parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('--user', action="store") parent_parser.add_argument('--password', action="store") child_parser = argparse.ArgumentParser(parents=[parent_parser], conflict_handler='resolve') child_parser.add_argument('--user', action="store", default="Guest") print child_parser.parse_args() Namespace(password=None, user='Guest')
In addition to the above approach to processing commands of different levels, there is also an alternative approach that allows you to combine the processing of all commands in one program using subparsers. Best of all, an example will tell you:
ap.py import argparse parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(help='List of commands')
This is what the program will issue with the key '-h':
usage: ap.py [-h] {list,create} ...
positional arguments:
{list,create} list of commands
list List contents
create Create a directory
optional arguments:
-h, --help show this help message and exit
In the example, the following things can be noted:
1.
positional arguments list, create, passed to the program - essentially subparsers;
2. the '--read-only' argument of the subparser create_parser is
optional , dir_name is necessary for both subparsers;
3. Help (help) is provided for both the parser and for each of the subparsers.
In general, argparse is a fairly powerful and lightweight library, providing, in my opinion, a very convenient interface for working with command line parameters. Next time I will try to cover issues such as file arguments (for more advanced work with files), variable lists of arguments, groups of arguments and more detail on the typing of arguments.
Thanks for attention.
Bibliography:
Why aren't getopt and optparse enough (PEP 389)Argparse positional and optional argumentsArgparse documentationParser for command-line options, arguments and sub-commands