5

I would like to store a bunch of variables under a Python namespace without creating a separate module. I notice that the result of ArgumentParser's parse_args() is a argparse.Namespace object. You can access the arguments through dot-syntax.

from argparse import ArgumentParser

parser = ArgumentParser()
# some arg definitions here...
args = parser.parse_args()  # returns a `argparse.Namespace` object

How can I create the equivalent of an argparse.Namespace? I know I can do something similar with a dict but I would like to use dot-syntax. Is there any built-in class that just lets you assign arbitrary attributes?

2
  • 2
    How about class Namespace(object): pass? Instantiate it, then just start assigning attributes. Commented Sep 17, 2014 at 17:02
  • Is there any built-in class that just lets you assign arbitrary attributes? - instances of any Python class that doesn't define __slots__ will let you assign arbitrary attributes. (That's the principle behind @dano's and @Bakuriu's suggestion of just using a class). Commented Sep 17, 2014 at 17:06

5 Answers 5

12

Starting with python3.3 you can use types.SimpleNamespace.

However an alternative is simply:

class Namespace(object):
    pass

namespaceA = Namespace()
namespaceA.x = 1

The full code for SimpleNamespace isn't much longer.


Note that you cannot simply use an object instance:

>>> o = object()
>>> o.x = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'x'

This is because instances of object do not have a __dict__ attribute:

>>> vars(object())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute

Which means you cannot set the attributes of an instance of object.

Any object subclass that does not have the __slots__ attribute set does have the __dict__ which is used (by default) to store/retrieve attributes:

>>> class Namespace(object):
...     pass
... 
>>> a = Namespace()
>>> a.x = 1     # same as as.__dict__['a'] = 1
>>> a.__dict__
{'x': 1}

For further information about attribute setting/lookup you should learn about descriptors.

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

6 Comments

+1 because I didn't know about types.SimpleNamespace, and it makes the intention clear
Great answer. I'm a little confused about something though-- why is it that I can assign arbitrary attributes to an instance of a new class that inherits from object, but not to an instance of object?
@Sean: Because object instances have no __dict__ in which to store new arbitrary attributes.
Bakuriu: If you changed your answer to class Namespace(object): it would work in both Python 2 and 3...
@SeanMackesey It works, but there are reason to avoid old-style classes, so, since it doesn't cost anything, you should always inherit from object in python2. I've decided to follow martineau advice and simply change the code myself (although I use only python3 currently). I also expanded a bit with regard to your observation about object.
|
2

A class can be used as a namespace, where the variables are class members:

class Namespace1:
    foo = 'a'
    bar = 5

To prevent callers from trying to instantiate, you can use a baseclass like:

class objectless(object):
    def __new__(cls, *args, **kwargs):
        raise RuntimeError('%s should not be instantiated' % cls)

And use it like:

class Namespace1(objectless):
    ...

4 Comments

Personally I think that overloading a class definition like this wouldn't be a good idea.
@martineau can you explain why?
Mainly because it's defining a weird class that can't be instantiated and is unnecessary given that there's a standard way to do such a thing in Python, namely by a defining a module, which doesn't require any tricky class definitions and is more explicit. There are other issues, like defining a regular function in this type of namespace would require using a @staticmethod decorator to prevent a TypeError: unbound method func() must be called with Namespace1 instance as first argument when calling it outside of the class definition via a Namespace1.func() (the most likely usage)
There are substantial benefits to reusing class rather than module machinery. Even in 2021, modules still only offer a fraction of the dunder methods available to classes – and even less for packages supporting all Python versions that have yet to hit EOL. Moreover, anyone opposed to "defining a weird class" should avoid importing anything from the standard library; most classes defined by the standard library are very weird and magical. That's okay, because "weird and magical" also means useful, succinct, and automated (e.g., enum.Enum, abc.ABCMeta).
1

If you want "the equivalent of an argparse.Namespace", use argparse.Namespace:

from argparse import Namespace

ns = Namespace(a=1)
print ns.a

Comments

0

It sounds like you want a python class. See the docs.

Depending on what you want exactly, you can define a bunch of variables as attributes of a class (either a variable of an instance or of the class itself) and access them that way.

Comments

0

If I'm understanding correctly, you want to dynamically add attributes to it. For example, a class parses command-line flags you access them directly like args.verbose, right? If so, you may be thinking of setattr() that lets you add arbitrary attributes.

class Foo(object):
    pass

foo = Foo()
setattr(foo, 'ack', 'bar')
print(foo.ack) # prints 'bar'

Comments

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.