Processing command-line arguments in ad-hoc python tools is one of those areas where I tend to just hack it together from scratch — simply because the effort of learning and understanding the relevant library packages not only seems to be more work than it is worth, but also and in particular more effort than “just doing it” by hand. I don’t want anything fancy, after all. I just want to get it done.
argparse module is certainly intimidating in this regard:
the official Python API reference documentation includes a pointer to
an equally official tutorial/howto document — clearly, nobody is
expected to understand the API from the reference alone. That does
not seem to bode well.
So it came as a considerable surprise to discover that
amazingly convenient. Here is how it works:
import argparse parser = argparse.ArgumentParser() parser.add_argument( 'val', help="text" ) # positional arg parser.add_argument( '-v', '--verbose', help="text" ) # optional arg args = parser.parse_args() print( args.val ) print( args.verbose )
That’s it. That’s shorter than any ad-hoc code I could come up with. And that’s not even mentioning any of the under-the-covers functionality that’s provided for free. (See below.)
argparse module makes a distinction between positional and
optional arguments. Positional arguments are generally required
and are not preceded by command-line flags. (Think of the file or
directory names passed to such Unix commands as
Positional command line arguments will be assigned in the order in
which they were defined using
Optional arguments are prefixed by one or two dashes. The
module considers arguments as positional or optional automatically,
based on the presence or absence of that prefix. Somewhat surprisingly,
positional and optional arguments can be freely intermingled on the
actual command line: it is not necessary for positional arguments to
always come last.
Much useful functionality can be accessed through keyword arguments
add_argument(). Here are some of the more useful ones:
help: Usage information for the argument.
type: Automatic type conversion (e.g.
type=int). The value must be a conversion function from string to the desired data type.
choices: An array of valid values (e.g.
default: A default value, if argument is missing (e.g.
True, the option is optional.
nargs: The number of arguments to consume. The arguments will be returned as a list. Its value is usually an integer, or
"+"to indicate 0 or 1, 0 or all, or at least 1 or all.
action: What to do with the argument. The default is
"store", meaning that the value is stored in the object returned by
parse_args(). Other possibilities include
"count", which returns the number of times the option has been given on the command line, and a few others (see below).
In addition to parsing the command-line arguments, the
also performs some input validation and constraint enforcement, as is
evident from the
required keywords. If input does not
meet the expected constraints, then
argparse automatically prints a
neatly formatted and rather verbose usage message to standard error.
In addition to the
help keyword, there are additional arguments that
can be used to customize the content and format of that message. The
--help) is provided by default and prints the usage
add_help=False to the
constructor to disable this behavior.)
The two keywords that may not be immediately clear are
nargs is set to an integer, then the corresponding
option will consume exactly that many parameters from the command
line, and will fail (printing a usage message) if either fewer or
more arguments are provided. The symbolic multiplier arguments are
available to deal with a variable number of arguments:
add_argument( 'files', nargs="+" ) expects at least one, but
possibly several arguments, and will store them, as a list, in
files attribute. (The module is fairly smart about edge
cases, such as an argument with
nargs="*" being followed
by another required positional argument and so on. Check the
reference documentation or experiment yourself.)
action keyword indicates what should be done with the
received command line argument. By default (
the value provided on the command line is simply stored as
attribute on the object returned by
action="count", which stores the number of
times the option was used in the command line: useful to set,
for example, verbosity levels through repeated use of a
The two actions
"store_false" are used to implement
command line switches, that is, command line arguments that don’t
take a value, but work simply by being present or absent. (Think of
rm -f.) The
"store" action expects an argument, and will fail
if none is provided. By contrast,
"store_true" will store the value
True if the option is present, and
False otherwise. As an
aside, the same effect could be achieved by using the
and checking whether the count is greater than zero. (Note that the
default value for
0. Use the
keyword to set the value to
0 in case the option is absent.)
That’s it. This should cover all situation in which I would have considered hacking up command line handling from scratch.
Of course there is more; the reference documentation has all the
details. With a basic idea of what
argparse is trying to achieve,
and how it goes about it, the reference page actually makes fairly
The main take-away, though, is this. For all the cases that one would consider implementing command line handling from scratch, the following lines of code (properly adapted) will do the trick:
import argparse parser = argparse.ArgumentParser() parser.add_argument( '-d', type=int ) parser.add_argument( '-f', '--force', action="store_true" ) parser.add_argument( '-v', '--verbose', action="count", default=0 ) parser.add_argument( 'things', nargs="*", help="help text" ) args = parser.parse_args() print( args.d, args.force, args.verbose, args.things )
That can’t be beat.