In this blog post, you will learn right way to parse command line arguments in python. For those who don’t know, command line arguments are passed into the script when executing the script from the command line. For example, the following executes a python script from the command line passing in a command line argument of a filename.
$ python .\process.py shakespeare.in -n 100
Before observing the right way to parse command line arguments, I’ll discuss the wrong way.
Parsing Command Line Arguments The Wrong Way
If you’re parsing command line arguments in python by accessing sys.argv, then you’re doing it the wrong way. The following is a sample python script that parses command line arguments by directly accessing sys.argv:
import sys
def main():
parse_cmd_line_args_the_wrong_way()
def parse_cmd_line_args_the_wrong_way():
if len(sys.argv) != 2 and len(sys.argv) != 4:
print_script_usage()
return
file_name = sys.argv[1]
lines = 0
if len(sys.argv) == 4:
if sys.argv[2] != "-n":
print_script_usage()
return
lines = int(sys.argv[3])
print("File name: " + str(file_name))
print("Lines: " + str(lines))
def print_script_usage():
print("python .\\process.py <filename> -n <number of lines>")
main()
Notice in this script, when you use sys.argv, you have all these conditional statements to check whether or not the correct number of command line arguments are passed in, and you also need to ensure that the correct switch “-n” is passed in from the command line. This method of processing the command line arguments unnecessarily clutters and complicates the script with sanitizing the command line arguments.
This is the output if you run without the -n flag:
$ python .\process.py shakespeare.in
File name: shakespeare.in
Lines: 0
This is the output if you run with the -n flag:
$ python .\process.py shakespeare.in -n 1000
File name: shakespeare.in
Lines: 1000
Thankfully, there is a much cleaner way to process command line arguments in Python.
Parsing Command Line Arguments The Right Way
To process command line arguments the correct way, you first need to install the argparse module, which you can simply do with the following command:
$ pip install argparse
The following solution is much cleaner than the command line parser that uses sys.argv:
import argparse
def main():
args = parse_cmd_line_args_the_right_way()
print("Filename: " + str(args.filename))
print("Lines: " + str(args.num_lines))
def parse_cmd_line_args_the_right_way():
parser = argparse.ArgumentParser(prog="process", description="Process a file", )
parser.add_argument("filename") # This is a positional argument
parser.add_argument("-n", "--num-lines", type=int, default=0) # Optional argument
return parser.parse_args()
main()
First, when parsing the command line arguments, the ArgumentParser object is instantiated, which is the following line of code:
parser = argparse.ArgumentParser(prog="process", description="Process a file", )
The arguments passed into the constructor of ArgumentParser are the following: the prog keyword is passed a string, which is the name of the script, and the description keyword is passed a string, which is a brief description of what the program does.
After the ArgumentParser object is instantiated, we add arguments that we expect to be passed in from the command line. The following line of code adds a positional argument to be parsed by the ArgumentParser:
parser.add_argument("filename")
The above line of code will instruct the ArgumentParser to expect the first argument of the command line to be the filename.
The next line of code adds an optional argument to the ArgumentParser.
parser.add_argument("-n", "--num-lines", type=int, default=0)
The optional argument can be configured using the -n switch or –num-lines switch, and it’s type is an integer, and the default value is 0, which is the value of num_lines when the number of lines is not passed into the script.
Afterwards, the following line of code executes:
return parser.parse_args()
This line of code parses the command line arguments, and returns a Namespace object that makes the values of the arguments accessible via the names of the arguments that were configured when invoking the add_argument methods.
In the main method, we can access the arguments that have been parsed. The following code snippet will access the filename and number of lines and display their values to the console:
def main():
args = parse_cmd_line_args_the_right_way()
print("Filename: " + str(args.filename))
print("Lines: " + str(args.num_lines))
The following is an execution of the script when no parameters are passed in:
$ python .\process.py
usage: process1 [-h] [-n NUM_LINES] filename
process: error: the following arguments are required: filename
The following is an execution of the script with the filename specified, but without specifying the number of lines:
$ python .\process.py shakespeare.in
Filename: shakespeare.in
Lines: 0
The following is an execution of the script with the filename specified and the number of lines to process specified:
$ python .\process.py shakespeare.in -n 1000
Filename: shakespeare.in
Lines: 1000
In this blog post, you have learned the wrong way to pythonically parse command line arguments, which is by using sys.argv and the right way to pythonically parse command line arguments, which is by using the argparse module. You have also learned the basics of using the argparse module.
For more blog posts just like this, subscribe, share, and buy me a coffee.
References
argparse — Parser for command-line options, arguments and sub-commands. (n.d.). Python Documentation. Retrieved December 13, 2023, from https://docs.python.org/3/library/argparse.html