425

If I want to use the results of argparse.ArgumentParser(), which is a Namespace object, with a method that expects a dictionary or mapping-like object (see collections.Mapping), what is the right way to do it?

C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> args.baz = 'yippee'
>>> args['baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Namespace' object has no attribute '__getitem__'
>>> dir(args)
['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '_
_format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__
', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'ba
r', 'baz', 'foo']

Is it proper to "reach into" an object and use its __dict__ property?

I would think the answer is no: __dict__ smells like a convention for implementation, but not for an interface, the way __getattribute__ or __setattr__ or __contains__ seem to be.

2
  • Did you try dict(args)? Why wouldn't the obvious way work? Commented Dec 14, 2021 at 18:27
  • 10
    @CharlieParker Did you try it? It raises TypeError: 'Namespace' object is not iterable. Commented Feb 16, 2023 at 17:39

4 Answers 4

650

You can access the namespace's dictionary with vars():

>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}

You can modify the dictionary directly if you wish:

>>> d['baz'] = 'store me'
>>> args.baz
'store me'

Yes, it is okay to access the __dict__ attribute. It is a well-defined, tested, and guaranteed behavior.

Sign up to request clarification or add additional context in comments.

7 Comments

The docs say: "The returned dictionary should not be modified: the effects on the corresponding symbol table are undefined." Which may only refer to the behavior of vars() (which is either locals() or globals()), but I'm not really sure.
hmm, I guess I don't really understand the difference between using vars() and __dict__
@delnan Someone had made an incorrect edit to the docs and made an over-broad admonition. The docs were subsequently corrected. See docs.python.org/2.7/library/functions.html#vars While there are some special cases that have read-only dictionaries (such as locals and class dictionary proxies), the rest of the cases are updateable. The vars(obj) call is synonymous with obj.__dict__. In the case of an argparse namespace, vars(args) gives direct access to an updateable dictionary.
Worth pointing out that going the vars route retains the order the arguments were defined by the parser unlike dict(args._get_kwargs())
@CharlieParker The dict() constructor builds new dictionaries from a list of tuples or from keyword arguments. In contrast, the vars() builtin accesses the _dict_ attribute to retrieve existing dictionaries enclosed by various objects include an argparse namespace.
|
134

Straight from the horse's mouth:

If you prefer to have dict-like view of the attributes, you can use the standard Python idiom, vars():

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

— The Python Standard Library, 16.4.4.6. The Namespace object

6 Comments

Still 'foo' misses '--'. Any idea to that?
@user2678074 this is intentional to match shell flags. The dashes are extraneous inside python execution.
vars(args) gives me TypeError: 'dict' object is not callable
@user5359531 you probably overwrote the global vars with a variable. You can use __builtins__.vars to access it directly, or del vars to stop shadowing it.
@NickT Minor correction: Python functions are statically scoped so if you shadow a global variable in a function, that identifier will always refer to the local variable within that function, even before it's assigned or after del. At the module scope del will work to "un-shadow" builtins.
|
6

Note that if you're trying to treat args as a dict to find out if it has an attribute, you can just do the following instead:

if hasattr(args, 'someProperty'):
    a.someProperty

more info on hasattr and similar answer to another question

Also, you can get the value if you prefer using the similar getattr method:

value = getattr(args, 'someProperty')

2 Comments

if 'someProperty' in args is more pythonic? Although, the getattr() is useful vs. vars(args)['someProperty'] which is brittle.
Also, I ended up here because I have command line args that are Python keywords (e.g., --continue) and trying to access args.continue is met with a "SyntaxError: invalid syntax" error. getattr(args, 'continue') is exactly what I was looking for: I was about to do vars(args)['continue'] but that didn't feel right, like there had to be a cleaner, more pythonic way.
0

Is it proper to "reach into" an object and use its dict property?

In general, I would say "no". However Namespace has struck me as over-engineered, possibly from when classes couldn't inherit from built-in types.

On the other hand, Namespace does present a task-oriented approach to argparse, and I can't think of a situation that would call for grabbing the __dict__, but the limits of my imagination are not the same as yours.

5 Comments

It is perfectly okay to access the __dict__ attribute. Introspection is fundamental to the language. The attribute was made public for a reason :-)
But everything in Python is "public". There are no distinctions (except the leading underscore convention) between the implementation variables used in an instance, and the public interface it presents. Especially in a dictionary-like object: the line between instance methods, and dictionary values which are functions, is a bit blurry.
If you're passing the arguments as named parameters? do_something(**args.__dict__)
why doesn't the obvious way work e.g. dict(args)? Or at least why is this not the top answer/recommended?
A reason to grab the __dict__ would be for logging purposes as Object of type Namespace is not JSON serializable

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.