Introduction
This tutorial explores how to add and manage multiple command-line arguments in Python using the argparse module. Command-line arguments allow users to customize how programs run without modifying the code itself. The argparse module simplifies this process by providing tools to define, validate, and parse these arguments.
By the end of this tutorial, you will understand how to create Python scripts that can accept various input parameters, making your applications more flexible and user-friendly.
Understanding Argparse Basics
The first step in working with command-line arguments is understanding the basics of the argparse module.
What is Argparse?
Argparse is a built-in Python module that makes it easy to write user-friendly command-line interfaces. It automatically generates help messages, handles errors, and converts command-line arguments to the appropriate data types for your program.
Creating Your First Script with Argparse
Let's start by creating a simple Python script that uses argparse. We'll create a file named hello.py that accepts a name as a command-line argument.
- Open the VSCode editor and create a new file by clicking "File" > "New File"
- Save the file as
hello.pyin the/home/labex/projectdirectory - Add the following code to the file:
import argparse
## Create the parser
parser = argparse.ArgumentParser(description='A simple greeting program')
## Add an argument
parser.add_argument('--name', type=str, default='World', help='Name to greet')
## Parse the arguments
args = parser.parse_args()
## Use the argument
print(f"Hello, {args.name}!")
This script demonstrates the three main steps for using argparse:
- Creating an ArgumentParser object
- Adding arguments to the parser
- Parsing the command-line arguments
Running Your Script
Let's run the script to see how it works:
- Open a terminal in the VSCode interface (Terminal > New Terminal)
- Run the script with the following command:
python3 hello.py
You should see this output:
Hello, World!
Now let's try passing a name:
python3 hello.py --name Alice
Output:
Hello, Alice!
Understanding Help Messages
One of the benefits of argparse is that it automatically generates help messages. Try running:
python3 hello.py --help
You should see output similar to:
usage: hello.py [-h] [--name NAME]
A simple greeting program
options:
-h, --help show this help message and exit
--name NAME Name to greet
This help message is automatically generated based on the description we provided when creating the parser and the help text we added to our argument.
Key Components of Argparse
Let's examine the main components in our script:
parser = argparse.ArgumentParser(description='...'): Creates a parser with a descriptionparser.add_argument('--name', ...): Adds an argument with the name '--name'type=str: Specifies that the argument should be a stringdefault='World': Sets a default value if the argument isn't providedhelp='Name to greet': Provides help text for the argumentargs = parser.parse_args(): Parses the command-line argumentsargs.name: Accesses the value of the 'name' argument
Now you understand the basics of using argparse to handle command-line arguments in Python.
Adding Multiple Argument Types
Now that you understand the basics, let's explore different types of arguments that can be added to your command-line interface.
Types of Arguments
Argparse supports several types of arguments:
- Positional arguments: Required arguments identified by their position
- Optional arguments: Arguments prefixed with -- (or -) that may have default values
- Flag arguments: Boolean arguments that are either present or absent
- Arguments with choices: Arguments limited to specific values
Let's create a new script that demonstrates these different argument types.
- Create a new file named
calculator.pyin the/home/labex/projectdirectory - Add the following code:
import argparse
## Create the parser
parser = argparse.ArgumentParser(description='A simple calculator')
## Add a positional argument
parser.add_argument('operation',
choices=['add', 'subtract', 'multiply', 'divide'],
help='Math operation to perform')
## Add optional arguments
parser.add_argument('--num1', type=float, required=True,
help='First number')
parser.add_argument('--num2', type=float, required=True,
help='Second number')
## Add a flag argument
parser.add_argument('--verbose', action='store_true',
help='Enable verbose output')
## Parse the arguments
args = parser.parse_args()
## Perform the calculation based on the operation
result = 0
if args.operation == 'add':
result = args.num1 + args.num2
elif args.operation == 'subtract':
result = args.num1 - args.num2
elif args.operation == 'multiply':
result = args.num1 * args.num2
elif args.operation == 'divide':
if args.num2 == 0:
print("Error: Cannot divide by zero")
exit(1)
result = args.num1 / args.num2
## Display the result
if args.verbose:
print(f"The result of {args.num1} {args.operation} {args.num2} is: {result}")
else:
print(f"Result: {result}")
Understanding the New Arguments
Let's examine the new argument types in this script:
Positional argument:
operation- must be one of 'add', 'subtract', 'multiply', or 'divide'parser.add_argument('operation', choices=['add', 'subtract', 'multiply', 'divide'], help='Math operation to perform')Optional arguments with required=True:
--num1and--num2- must be provided by the userparser.add_argument('--num1', type=float, required=True, help='First number')Flag argument:
--verbose- when present, enables verbose outputparser.add_argument('--verbose', action='store_true', help='Enable verbose output')
Testing the Calculator
Run the calculator with different arguments to see how it works:
python3 calculator.py add --num1 5 --num2 3
Output:
Result: 8.0
Try with the verbose flag:
python3 calculator.py multiply --num1 4 --num2 7 --verbose
Output:
The result of 4.0 multiply 7.0 is: 28.0
Try the division operation:
python3 calculator.py divide --num1 10 --num2 2
Output:
Result: 5.0
If you forget a required argument, argparse will show an error:
python3 calculator.py add --num1 5
Output:
usage: calculator.py [-h] [--num1 NUM1] [--num2 NUM2] [--verbose]
{add,subtract,multiply,divide}
calculator.py: error: the following arguments are required: --num2
Key Points About Argument Types
- Positional arguments don't need a prefix and are identified by their position
- The
choicesparameter restricts the valid values for an argument - The
required=Trueparameter makes an optional argument mandatory - The
action='store_true'parameter creates a flag that's False by default and True when specified - The
typeparameter converts the input to the specified type (float in our example)
Now you understand how to use different types of arguments with argparse.
Advanced Argument Configurations
Now let's explore more advanced configurations for arguments, including:
- Arguments that accept multiple values
- Arguments with custom validation
- Arguments with default values
- Arguments with short names (single-letter aliases)
Creating a File Processing Script
Let's create a script that demonstrates these advanced configurations by building a file processing utility.
- Create a new file named
file_processor.pyin the/home/labex/projectdirectory - Add the following code:
import argparse
import os
def validate_file(filename):
"""Validate that the file exists."""
if not os.path.exists(filename):
raise argparse.ArgumentTypeError(f"File {filename} does not exist")
return filename
## Create the parser
parser = argparse.ArgumentParser(description='Process text files')
## Multiple values
parser.add_argument('-f', '--files',
type=validate_file,
nargs='+',
help='Input files to process')
## Argument with short name
parser.add_argument('-o', '--output',
default='output.txt',
help='Output file (default: output.txt)')
## Choices with default
parser.add_argument('-m', '--mode',
choices=['read', 'count', 'stats'],
default='read',
help='Processing mode (default: read)')
## Custom validation for a positive integer
def positive_int(value):
ivalue = int(value)
if ivalue <= 0:
raise argparse.ArgumentTypeError(f"{value} is not a positive integer")
return ivalue
parser.add_argument('-l', '--lines',
type=positive_int,
default=10,
help='Number of lines to process (default: 10)')
## Parse arguments
args = parser.parse_args()
## Process files based on mode
for file in args.files if args.files else []:
print(f"Processing file: {file}")
with open(file, 'r') as f:
content = f.readlines()
if args.mode == 'read':
## Read mode: output first N lines
print(f"First {args.lines} lines:")
for i, line in enumerate(content[:args.lines]):
print(f"{i+1}: {line.strip()}")
elif args.mode == 'count':
## Count mode: count lines, words, chars
line_count = len(content)
word_count = sum(len(line.split()) for line in content)
char_count = sum(len(line) for line in content)
print(f"Lines: {line_count}")
print(f"Words: {word_count}")
print(f"Characters: {char_count}")
elif args.mode == 'stats':
## Stats mode: line length statistics
if content:
line_lengths = [len(line.strip()) for line in content]
avg_length = sum(line_lengths) / len(line_lengths)
max_length = max(line_lengths)
min_length = min(line_lengths)
print(f"Average line length: {avg_length:.2f}")
print(f"Shortest line: {min_length} characters")
print(f"Longest line: {max_length} characters")
else:
print("File is empty")
print("-" * 30)
print(f"Results will be saved to: {args.output}")
## Note: In a real application, we would actually write to the output file
Understanding the Advanced Configurations
Let's examine the advanced argument configurations:
Multiple values with
nargs='+':parser.add_argument('-f', '--files', type=validate_file, nargs='+', help='Input files to process')The
nargs='+'parameter allows the user to provide one or more file arguments.Custom validation function:
def validate_file(filename): if not os.path.exists(filename): raise argparse.ArgumentTypeError(f"File {filename} does not exist") return filenameThis function checks if the specified file exists before proceeding.
Short aliases with
-o:parser.add_argument('-o', '--output', default='output.txt', help='Output file (default: output.txt)')The
-oprovides a shorter way to specify the--outputargument.Choices with default value:
parser.add_argument('-m', '--mode', choices=['read', 'count', 'stats'], default='read', help='Processing mode (default: read)')This limits the mode to specific values while providing a default.
Creating Sample Test Files
Let's create two sample files to test our script:
- Create a sample file named
sample1.txt:
echo -e "This is the first line.\nThis is the second line.\nThis is the third line.\nThis is the fourth line.\nThis is the fifth line." > /home/labex/project/sample1.txt
- Create another sample file named
sample2.txt:
echo -e "Lorem ipsum dolor sit amet.\nConsectetur adipiscing elit.\nSed do eiusmod tempor incididunt.\nUt labore et dolore magna aliqua." > /home/labex/project/sample2.txt
Testing the File Processor
Now let's run the script with different arguments:
- Basic usage with one file:
python3 file_processor.py -f sample1.txt
Output:
Processing file: sample1.txt
First 10 lines:
1: This is the first line.
2: This is the second line.
3: This is the third line.
4: This is the fourth line.
5: This is the fifth line.
------------------------------
Results will be saved to: output.txt
- Process multiple files:
python3 file_processor.py -f sample1.txt sample2.txt
Output:
Processing file: sample1.txt
First 10 lines:
1: This is the first line.
2: This is the second line.
3: This is the third line.
4: This is the fourth line.
5: This is the fifth line.
------------------------------
Processing file: sample2.txt
First 10 lines:
1: Lorem ipsum dolor sit amet.
2: Consectetur adipiscing elit.
3: Sed do eiusmod tempor incididunt.
4: Ut labore et dolore magna aliqua.
------------------------------
Results will be saved to: output.txt
- Use the count mode:
python3 file_processor.py -f sample1.txt -m count
Output:
Processing file: sample1.txt
Lines: 5
Words: 25
Characters: 135
------------------------------
Results will be saved to: output.txt
- Use the stats mode:
python3 file_processor.py -f sample2.txt -m stats
Output:
Processing file: sample2.txt
Average line length: 29.25
Shortest line: 22 characters
Longest line: 37 characters
------------------------------
Results will be saved to: output.txt
- Limit the number of lines:
python3 file_processor.py -f sample1.txt -l 2
Output:
Processing file: sample1.txt
First 2 lines:
1: This is the first line.
2: This is the second line.
------------------------------
Results will be saved to: output.txt
Key Points About Advanced Configurations
nargs='+'allows for multiple argument values- Custom validation functions help ensure valid input
- Short argument names (single-letter aliases) provide convenience
- Default values simplify usage for common scenarios
- The
choicesparameter restricts input to valid options
Now you have learned how to configure advanced argument options in your command-line scripts.
Building a Complete Command-Line Tool
In this step, we'll combine everything we've learned to build a complete command-line tool. Let's create a simple task manager that allows users to add, list, and delete tasks using command-line arguments.
Creating the Task Manager
- Create a new file named
task_manager.pyin the/home/labex/projectdirectory - Add the following code:
import argparse
import json
import os
## File to store tasks
TASKS_FILE = "/home/labex/project/tasks.json"
def load_tasks():
"""Load tasks from the JSON file."""
if os.path.exists(TASKS_FILE):
with open(TASKS_FILE, 'r') as f:
try:
return json.load(f)
except json.JSONDecodeError:
return []
return []
def save_tasks(tasks):
"""Save tasks to the JSON file."""
with open(TASKS_FILE, 'w') as f:
json.dump(tasks, f, indent=2)
def main():
## Create the main parser
parser = argparse.ArgumentParser(description='Task Manager CLI')
subparsers = parser.add_subparsers(dest='command', help='Command to run')
## Add command
add_parser = subparsers.add_parser('add', help='Add a new task')
add_parser.add_argument('title', help='Task title')
add_parser.add_argument('-p', '--priority',
choices=['low', 'medium', 'high'],
default='medium',
help='Task priority (default: medium)')
add_parser.add_argument('-d', '--due',
help='Due date (format: YYYY-MM-DD)')
## List command
list_parser = subparsers.add_parser('list', help='List all tasks')
list_parser.add_argument('-p', '--priority',
choices=['low', 'medium', 'high'],
help='Filter tasks by priority')
list_parser.add_argument('-s', '--sort',
choices=['priority', 'title'],
default='priority',
help='Sort tasks by criteria (default: priority)')
## Delete command
delete_parser = subparsers.add_parser('delete', help='Delete a task')
delete_parser.add_argument('task_id', type=int, help='Task ID to delete')
## Parse arguments
args = parser.parse_args()
## Load existing tasks
tasks = load_tasks()
## Handle commands
if args.command == 'add':
## Add a new task
new_task = {
'id': len(tasks) + 1,
'title': args.title,
'priority': args.priority,
'due': args.due
}
tasks.append(new_task)
save_tasks(tasks)
print(f"Task added: {new_task['title']} (ID: {new_task['id']})")
elif args.command == 'list':
## List tasks
if not tasks:
print("No tasks found.")
return
## Filter by priority if specified
if args.priority:
filtered_tasks = [t for t in tasks if t['priority'] == args.priority]
else:
filtered_tasks = tasks
## Sort tasks
if args.sort == 'priority':
## Custom priority sorting
priority_order = {'high': 0, 'medium': 1, 'low': 2}
sorted_tasks = sorted(filtered_tasks, key=lambda x: priority_order[x['priority']])
else:
## Sort by title
sorted_tasks = sorted(filtered_tasks, key=lambda x: x['title'])
## Display tasks
print("ID | Title | Priority | Due Date")
print("-" * 50)
for task in sorted_tasks:
due_date = task['due'] if task['due'] else 'N/A'
print(f"{task['id']:2} | {task['title'][:20]:<20} | {task['priority']:<8} | {due_date}")
elif args.command == 'delete':
## Delete a task
task_id = args.task_id
task_found = False
for i, task in enumerate(tasks):
if task['id'] == task_id:
del tasks[i]
task_found = True
break
if task_found:
save_tasks(tasks)
print(f"Task {task_id} deleted.")
else:
print(f"Task {task_id} not found.")
else:
## No command specified
parser.print_help()
if __name__ == "__main__":
main()
Understanding the Task Manager
This script demonstrates several advanced features of argparse:
- Subparsers - Creating command-specific argument sets
- Command-specific arguments - Different arguments for add, list, and delete commands
- Nested validation - Priority choices limited to specific values
- Default values - Providing sensible defaults for optional arguments
Testing the Task Manager
Let's run the script with different commands to see how it works:
- Adding tasks:
python3 task_manager.py add "Complete Python tutorial" -p high -d 2023-12-31
Output:
Task added: Complete Python tutorial (ID: 1)
Add a few more tasks:
python3 task_manager.py add "Read documentation" -p medium
python3 task_manager.py add "Take a break" -p low -d 2023-12-25
- Listing tasks:
python3 task_manager.py list
Output:
ID | Title | Priority | Due Date
--------------------------------------------------
1 | Complete Python tutor | high | 2023-12-31
2 | Read documentation | medium | N/A
3 | Take a break | low | 2023-12-25
- Listing tasks with filtering and sorting:
python3 task_manager.py list -s title
Output:
ID | Title | Priority | Due Date
--------------------------------------------------
1 | Complete Python tutor | high | 2023-12-31
2 | Read documentation | medium | N/A
3 | Take a break | low | 2023-12-25
- Filtering by priority:
python3 task_manager.py list -p high
Output:
ID | Title | Priority | Due Date
--------------------------------------------------
1 | Complete Python tutor | high | 2023-12-31
- Deleting a task:
python3 task_manager.py delete 2
Output:
Task 2 deleted.
Verify the task was deleted:
python3 task_manager.py list
Output:
ID | Title | Priority | Due Date
--------------------------------------------------
1 | Complete Python tutor | high | 2023-12-31
3 | Take a break | low | 2023-12-25
Getting Help for Subcommands
Argparse automatically generates help for each subcommand:
python3 task_manager.py add --help
Output:
usage: task_manager.py add [-h] [-p {low,medium,high}] [-d DUE] title
positional arguments:
title Task title
options:
-h, --help show this help message and exit
-p {low,medium,high}, --priority {low,medium,high}
Task priority (default: medium)
-d DUE, --due DUE Due date (format: YYYY-MM-DD)
Key Points About Subparsers
- Subparsers create command-specific argument sets
- Each subparser can have its own arguments
- The
destparameter specifies where the command name will be stored - Help messages are automatically generated for each subcommand
- You can mix positional and optional arguments in subparsers
You now have a fully functional command-line tool that demonstrates the power and flexibility of argparse for handling complex argument scenarios.
Summary
In this tutorial, you learned how to use Python's argparse module to handle command-line arguments effectively. You explored:
- Basic argparse functionality and creating simple scripts
- Different types of arguments: positional, optional, flags, and choices
- Advanced argument configurations like multiple values and custom validation
- Building a complete command-line tool with subcommands
These skills allow you to create more flexible and user-friendly Python applications that can be configured through command-line arguments without modifying the code.
Command-line argument parsing is an essential skill for Python developers who want to build professional-quality tools and utilities. The argparse module provides a robust and standardized way to implement this functionality in your scripts.
Now you can apply these techniques to your own Python projects to make them more versatile and accessible to users.



