Python
argparse
dictionary
programming
tutorial

What is the right way to treat Python argparse.Namespace as a dictionary?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Python's argparse.Namespace stores parsed command-line arguments as attributes (accessed with dot notation like args.verbose). To treat it as a dictionary, use vars(args), which returns the __dict__ of the namespace object. This is the official, documented way to convert between the two representations. The returned dictionary is the actual internal storage — modifying it also modifies the namespace, and vice versa.

Basic Conversion with vars()

python
1import argparse
2
3parser = argparse.ArgumentParser()
4parser.add_argument('--name', default='World')
5parser.add_argument('--count', type=int, default=1)
6parser.add_argument('--verbose', action='store_true')
7
8args = parser.parse_args(['--name', 'Alice', '--count', '3'])
9
10# Convert to dictionary
11args_dict = vars(args)
12print(args_dict)
13# {'name': 'Alice', 'count': 3, 'verbose': False}
14
15# Access as dictionary
16print(args_dict['name'])  # Alice
17
18# Access as attribute (still works)
19print(args.name)          # Alice

vars() Returns a Live Reference

The dictionary from vars(args) is the same object as args.__dict__. Changes to the dictionary affect the namespace and vice versa:

python
1args_dict = vars(args)
2
3# Modify via dictionary
4args_dict['name'] = 'Bob'
5print(args.name)  # Bob — namespace updated too
6
7# Modify via attribute
8args.count = 10
9print(args_dict['count'])  # 10 — dict updated too
10
11# To get an independent copy:
12args_copy = dict(vars(args))
13# or
14import copy
15args_copy = copy.copy(vars(args))

Why Not Use dict Directly?

vars(args) and args.__dict__ return the same object, but vars() is the Pythonic way:

python
1# Both work, but vars() is preferred
2d1 = vars(args)
3d2 = args.__dict__
4
5assert d1 is d2  # Same object
6
7# vars() is recommended by the argparse documentation
8# __dict__ is an implementation detail that happens to work

Practical Use Cases

Pass Arguments to a Function as kwargs

python
1def configure(name, count, verbose):
2    print(f"Configuring {name} with count={count}, verbose={verbose}")
3
4args = parser.parse_args()
5configure(**vars(args))
6# Unpacks: configure(name='Alice', count=3, verbose=False)

Merge with Default Configuration

python
1defaults = {
2    'name': 'default',
3    'count': 1,
4    'verbose': False,
5    'output': 'result.txt',  # Not an argparse argument
6}
7
8# CLI args override defaults
9config = {**defaults, **vars(args)}
10print(config)
11# {'name': 'Alice', 'count': 3, 'verbose': False, 'output': 'result.txt'}

Serialize to JSON

python
1import json
2
3args = parser.parse_args()
4config_json = json.dumps(vars(args), indent=2)
5print(config_json)
6# {
7#   "name": "Alice",
8#   "count": 3,
9#   "verbose": false
10# }
11
12# Save to file
13with open('config.json', 'w') as f:
14    json.dump(vars(args), f, indent=2)

Filter Arguments

python
1args = parser.parse_args()
2args_dict = vars(args)
3
4# Only non-default arguments
5non_default = {k: v for k, v in args_dict.items() if v is not None}
6
7# Only string arguments
8string_args = {k: v for k, v in args_dict.items() if isinstance(v, str)}

Convert Back to Namespace

python
1# Dictionary to Namespace
2config = {'name': 'Alice', 'count': 3, 'verbose': True}
3args = argparse.Namespace(**config)
4
5print(args.name)     # Alice
6print(args.verbose)  # True

Working with Subparsers

python
1parser = argparse.ArgumentParser()
2subparsers = parser.add_subparsers(dest='command')
3
4run_parser = subparsers.add_parser('run')
5run_parser.add_argument('--fast', action='store_true')
6
7test_parser = subparsers.add_parser('test')
8test_parser.add_argument('--coverage', action='store_true')
9
10args = parser.parse_args(['run', '--fast'])
11print(vars(args))
12# {'command': 'run', 'fast': True}

Checking if an Argument Was Provided

python
1parser = argparse.ArgumentParser()
2parser.add_argument('--port', type=int, default=None)
3args = parser.parse_args()
4
5# Check via dictionary
6if 'port' in vars(args) and vars(args)['port'] is not None:
7    print(f"Using port {args.port}")
8
9# Simpler attribute check
10if args.port is not None:
11    print(f"Using port {args.port}")

Common Pitfalls

  • Mutating vars(args) mutates the namespace: The dictionary is a live reference, not a copy. If you need an independent dictionary, use dict(vars(args)) to create a shallow copy.
  • Non-serializable argument types: vars(args) may contain types that json.dumps cannot handle (e.g., pathlib.Path, file objects from type=argparse.FileType). Convert these before serialization.
  • Using **vars(args) with functions that have extra parameters: If the function accepts **kwargs, all arguments pass through. If it has fixed parameters, extra argparse arguments raise TypeError: unexpected keyword argument.
  • None vs not provided: argparse uses None as the default for optional arguments. There is no built-in way to distinguish "user passed --port None" from "user did not pass --port". Use a sentinel default like argparse.SUPPRESS or a custom default object.
  • Namespace comparison gotcha: Two Namespace objects with the same attributes are equal (==), but converting to dict and comparing is safer when attributes might have been dynamically added.

Summary

  • Use vars(args) to convert argparse.Namespace to a dictionary — this is the official approach
  • The returned dictionary is a live reference to the namespace's __dict__, not a copy
  • Use **vars(args) to unpack arguments as keyword arguments to functions
  • Use argparse.Namespace(**dict) to convert a dictionary back to a namespace
  • Create a copy with dict(vars(args)) if you need to modify the dictionary without affecting the namespace

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms