459

I want to create a dynamic object in Python and then add attributes to it. This didn't work:

obj = object()
obj.somefield = "somevalue"

AttributeError: 'object' object has no attribute 'somefield'


For details on why it doesn't work, see Can't set attributes on instance of "object" class.

2
  • 9
    Why are you doing this? A generic "object" has no actual meaning. What is the meaning of the thing you are creating? Why is it not a proper class or namedtuple? Commented May 13, 2010 at 14:45
  • 3
    The example is not minimal and confusing for me or I just don't see why you don't work with some a = object() and you need obj.a = object(). Again I am talking about the example, in your actual code an object inside an object might be useful. Commented Jul 25, 2017 at 2:51

19 Answers 19

491

The built-in object can be instantiated but can't have any attributes set on it. (I wish it could, for this exact purpose.) This is because it doesn't have a __dict__ to hold the attributes.


I generally just do this:

class Object(object):
    pass

obj = Object()
obj.somefield = "somevalue"

But consider giving the Object class a more meaningful name, depending on what data it holds.


Another possibility is to use a sub-class of dict that allows attribute access to get at the keys:

class AttrDict(dict):
    def __getattr__(self, key):
        return self[key]

    def __setattr__(self, key, value):
        self[key] = value

obj = AttrDict()
obj.somefield = "somevalue"

To instantiate the object attributes using a dictionary:

d = {"a": 1, "b": 2, "c": 3}

for k, v in d.items():
    setattr(obj, k, v)
Sign up to request clarification or add additional context in comments.

2 Comments

it can be instantiated, just not used for anything useful once it has been done. foo = object() works, but you just can't do much of anything with it
great answer, the only thing I changed was to use Struct as the name of the class to make it more obvious. Saved me a ton of typing [" and "], Cheers!
300

You could use my ancient Bunch recipe, but if you don't want to make a "bunch class", a very simple one already exists in Python -- all functions can have arbitrary attributes (including lambda functions). So, the following works:

obj = lambda: None
obj.somefield = 'somevalue'

Whether the loss of clarity compared to the venerable Bunch recipe is OK, is a style decision I will of course leave up to you.

15 Comments

@naught101, a function is an object, in Python, so your objection is unfathomable.
@naught101, avoiding the creation of a new type (reusing an existing one) does not complicate, it simplifies. Nowadays on might actually prefer from argparse import Namespace though I wish it lived elsewhere *e.g, collection) -- again reusing a now-existing type, just a better one, and still avoiding new-type creation. But, it wasn't there then:-).
I was looking for exactly this functionality, but from argparse import Namespace is so counter intuitive. Has it ever been suggested to move it, indeed, to collections?
See answer below from "J F Sebastian" regarding SimpleNamespace from the types module. If your version of python supports it, this is the best solution (and exactly what SimpleNamespace is designed for)
Dude, the OP's question clearly implies that someobject has been previously set -- indeed it STARTS by assigning it.
|
200

There is types.SimpleNamespace class in Python 3.3+:

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtuple, typing.NamedTuple could be used for immutable objects. PEP 557 -- Data Classes suggests a mutable alternative.

For a richer functionality, you could try attrs package. See an example usage. pydantic may be worth a look too.

4 Comments

If you need something that works with Python 2.7, you can also try the argparse.Namespace class
@Roel attrs package supports Python 2.7
This seems a better solution to me than unittest.mock; the latter is a bit too heavy-weight and a bit more malleable. With a mock object, simply assigning to an attribute will cause it to spring into existence; SimpleNamespace will resist that.
That's a handy oneliner: obj = SimpleNamespace(x=1, y='abc', somefield=somevalue)
64

You can also use a class object directly; it creates a namespace:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')

4 Comments

I don't understand why this is not the top answer?
@confiq it doesn't say anything that the top answer is missing.
@KarlKnechtel This answer uses a custom class directly, while the top answer instantiates a custom class.
Easy to make mistakes with this (e.g. reusing the class). Instantiating an object is much more robust.
59

The mock module is basically made for that.

import mock
obj = mock.Mock()
obj.a = 5

3 Comments

Disadvantge is that's an external dependency
unittest.Mock is a part of the standard library since Python 3.3 (docs.python.org/3/library/unittest.mock.html)
Depends on the usage of your code I think. If it is production code, I would not want some mock in it. Just feels weird to me.
38

There are a few ways to reach this goal. Basically you need an object which is extendable.

obj = type('Test', (object,), {})  
obj.b = 'fun'
obj = lambda:None
obj.b = 'fun'
class Test:
  pass

obj = Test()
obj.b = 'fun'

1 Comment

obj.a = type('', (), {})
25

Now you can do (not sure if it's the same answer as evilpie):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

1 Comment

@evilpie's answer sets attributes directly on MyObject (the class), not its instance like yours.
23

Try the code below:

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']

4 Comments

Can you explain more of what this does? while the code may be useful for solving this problem, having it explained can go a lot further than just one problem.
@DeadChex Clearly it creates a new Class(object) which is a empty class with object properties, and stores the attributes inside the class. This is even better than install more modules, or rely in lambdas.
Not sure why this does not have more upvotes. Is there a reason not to use this for a basic container class? Seems to work fine in Python 2.7, 2.6, and 3.4
So how does this set the value of an attribute whose name is contained in a separate variable?
10

as docs say:

Note: object does not have a __dict__, so you can’t assign arbitrary attributes to an instance of the object class.

You could just use dummy-class instance.

Comments

4

These solutions are very helpful during testing. Building on everyone else's answers I do this in Python 2.7.9 (without staticmethod I get a TypeError (unbound method...):

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

Comments

3

If we can determine and aggregate all the attributes and values together before creating the nested object, then we could create a new class that takes a dictionary argument on creation.

# python 2.7

class NestedObject():
    def __init__(self, initial_attrs):
        for key in initial_attrs:
            setattr(self, key, initial_attrs[key])

obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'

We can also allow keyword arguments. See this post.

class NestedObject(object):
    def __init__(self, *initial_attrs, **kwargs):
        for dictionary in initial_attrs:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])


obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')

Comments

2

To create an object from a dictionary:

class Struct(object):
    def __init__(self, d):
        for key in d.keys():
            self.__setattr__(key, d[key])

Usage:

>>> obj = Struct({'a': 1, 'b': 2})
>>> obj.a
1

2 Comments

Another way is types.SimpleNamespace(**d).
Thanks for sharing! This is why I always scroll down.
1

Which objects are you using? Just tried that with a sample class and it worked fine:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

And I got 123 as the answer.

The only situation where I see this failing is if you're trying a setattr on a builtin object.

Update: From the comment this is a repetition of: Why can't you add attributes to object in python?

1 Comment

b.c is set to object() not a defined class
1

I think the easiest way is through the collections module.

import collections
FinanceCtaCteM = collections.namedtuple('FinanceCtaCte', 'forma_pago doc_pago get_total')
def get_total(): return 98989898
financtacteobj = FinanceCtaCteM(forma_pago='CONTADO', doc_pago='EFECTIVO',
                                get_total=get_total)

print financtacteobj.get_total()
print financtacteobj.forma_pago
print financtacteobj.doc_pago

Comments

1

if you are looking for chain assignment, to do things such as django model template abstract attribute assigning:

from types import SimpleNamespace


def assign(target, *args, suffix):
    ls = target
    for i in range(len(args) - 1):
        a = args[i]
        ns = SimpleNamespace()
        setattr(ls, a, ns)
        ls = ns
    setattr(ls, args[-1], suffix)
    return ls


a = SimpleNamespace()
assign(a, 'a', 'b', 'c', suffix={'name': 'james'})
print(a.a.b.c)
# {'name': 'james'}

which allows you to pass model as a target, and assign end attribute to it.

Comments

1

You can use Alex Martelli's venerable Bunch class. My favourite variety of it looks like

class Bunch(dict):
    def __init__(self, **kwds):
        self.update(kwds)
        self.__dict__ = self

By comparison to the other answers here, this solution allows you to construct such a class inline, as an expression:

map_data = Bunch(
        directions=[d for d in parsed_data.directions],
        connections={c.start: Bunch(L=c.left, R=c.right) for c in parsed_data.connections})
print(map_data)

Also, because Bunch is a dict, this prints something nice!

{'directions': ['R', 'L'], 'connections': {'AAA': {'L': 'BBB', 'R': 'CCC'}, 'BBB': {'L': 'DDD', 'R': 'EEE'}, 'CCC': {'L': 'ZZZ', 'R': 'GGG'}, 'DDD': {'L': 'DDD', 'R': 'DDD'}, 'EEE': {'L': 'EEE', 'R': 'EEE'}, 'GGG': {'L': 'GGG', 'R': 'GGG'}, 'ZZZ': {'L': 'ZZZ', 'R': 'ZZZ'}}}

By comparison, a custom Object class (such as the current top answer), prints something not as nice:

<__main__.Object object at 0x7025cae62b90>

The fact that you can use Bunch as an expression also allows you to use it part of a list or dictionary comprehension, as above:

connections={c.start: Bunch(L=c.left, R=c.right) for c in parsed_data.connections})`

This would be quite difficult to do with any of the other solutions posted here.

You can also construct such an object directly from a dictionary:

my_dict = {'directions': 'LRLRLL', 'connections': []}
map_data = Bunch(**my_dict)
print(map_data)

Another big advantage of this solution over any of the other posted solutions is that your object is a dictionary, as well as an object. This means:

  1. If your existing code is using dictionary syntax (map_data['directions']), you can migrate over to Bunch, and update the existing code gradually.
  2. Debugging is awesome! You can print, pretty print, iterate over keys / values, everything you would want to do with a dict!

Comments

0

Coming to this late in the day but here is my pennyworth with an object that just happens to hold some useful paths in an app but you can adapt it for anything where you want a sorta dict of information that you can access with getattr and dot notation (which is what I think this question is really about):

import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

This is cool because now:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

So this uses the function object like the above answers but uses the function to get the values (you can still use (getattr, x_path, 'repository') rather than x_path('repository') if you prefer).

Comments

-2
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

Comments

-3

Other way i see, this way:

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

2 Comments

you can add in append the name attr this di[name].append([at,cmds.getAttr(name+'.'+at)[0]])
This is adding a very big non-standard dependency while a simple class a: pass gives all the power required.

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.