15

I know what namespaces are. But when running

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('bar')
parser.parse_args(['XXX']) # outputs:  Namespace(bar='XXX')

What kind of object is Namespace(bar='XXX')? I find this totally confusing.

Reading the argparse docs, it says "Most ArgumentParser actions add some value as an attribute of the object returned by parse_args()". Shouldn't this object then appear when running globals()? Or how can I introspect it?

8
  • AFAIK, it's a dictionary-like object whose class is called Namespace. It has nothing to do with global or local namespace Commented Mar 16, 2022 at 16:27
  • "Shouldn't this object then appear when running globals()" huh? No, why do you think that would be true? Commented Mar 16, 2022 at 16:29
  • 1
    It doesn't appear in globals() because you didn't assign the return value of parser.parse_args to a global variable. If you write args = parser.parse_args(['XXX']), then globals()['args'] is the Namespace object. Commented Mar 16, 2022 at 16:36
  • 1
    As a general rule, functions to not inject names to any scope; only assignments do that. Commented Mar 16, 2022 at 16:37
  • 1
    One of the things the Namespace class provides is a __repr__ function that produces the nice representation. You can see the source code for yourself. (Note that the __repr__ is inherited from _AttributeHolder, which acts as a base class for serveral classes defined in argparse.) Commented Mar 16, 2022 at 16:41

3 Answers 3

18

Samwise's answer is very good, but let me answer the other part of the question.

Or how can I introspect it?

Being able to introspect objects is a valuable skill in any language, so let's approach this as though Namespace is a completely unknown type.

>>> obj = parser.parse_args(['XXX']) # outputs:  Namespace(bar='XXX')

Your first instinct is good. See if there's a Namespace in the global scope, which there isn't.

>>> Namespace
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Namespace' is not defined

So let's see the actual type of the thing. The Namespace(bar='XXX') printer syntax is coming from a __str__ or __repr__ method somewhere, so let's see what the type actually is.

>>> type(obj)
<class 'argparse.Namespace'>

and its module

>>> type(obj).__module__
'argparse'

Now it's a pretty safe bet that we can do from argparse import Namespace and get the type. Beyond that, we can do

>>> help(argparse.Namespace)

in the interactive interpreter to get detailed documentation on the Namespace class, all with no Internet connection necessary.

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

1 Comment

Ohhh, this is really nice, just on my level of knowledge :). +1
6

It's simply a container for the data that parse_args generates.

https://docs.python.org/3/library/argparse.html#argparse.Namespace

This class is deliberately simple, just an object subclass with a readable string representation.

Just do parser.parse_args(...).bar to get the value of your bar argument. That's all there is to that object. Per the doc, you can also convert it to a dict via vars().

The symbol Namespace doesn't appear when running globals() because you didn't import it individually. (You can access it as argparse.Namespace if you want to.) It's not necessary to touch it at all, though, because you don't need to instantiate a Namespace yourself. I've used argparse many times and until seeing this question never paid attention to the name of the object type that it returns -- it's totally unimportant to the practical applications of argparse.

2 Comments

Great answer too! I agree I don't need to touch it, I am just bothered that here is something new in terms of "behavior" that I don't understand. I'm actually still confused by argparse.Namespace means. If I have an object, with the dot I can access and attribute or a method. If I have a module, with an attribute I can access something from that module, so that means Namespace is something that is defined there (and it indeed is, I checked it). But now I'm confused: If it is already defined in that module, how can parse_args modify it?
parse_args creates and returns an instance of the Namespace class; it doesn't modify a central Namespace object.
4

Namespace is basically just a bare-bones class, on whose instances you can define attributes, with a few niceties:

  • A nice __repr__
  • Only keyword arguments can be used to instantiate it, preventing "anonymous" attributes.
  • A convenient method to check if an attribute exists (foo in Namespace(bar=3) evaluates to False)
  • Equality with other Namespace instances based on having identical attributes and attribute values. (E.g. ,Namespace(foo=3, bar=5) == Namespace(bar=5, foo=3))

Instances of Namespace are returned by parse_args:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('bar')
args = parser.parse_args(['XXX'])

assert args.bar == 'XXX'

1 Comment

Thanks, this was also really insightful +1 :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.