How can I create an object and add attributes to it?
I want to create a dynamic object (inside another object) in Python and then add attributes to it.
I tried:
obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')
but this didn't work.
Any ideas?
edit:
I am setting the attributes from a for
loop which loops through a list of values, e.g.
params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()
for p in params:
obj.a.p # where p comes from for loop variable
In the above example I would get obj.a.attr1
, obj.a.attr2
, obj.a.attr3
.
I used the setattr
function because I didn't know how to do obj.a.NAME
from a for
loop.
How would I set the attribute based on the value of p
in the example above?
The built-in object
can be instantiated but can't have any attributes set on it. (I wish it could, for this exact purpose.) It doesn't have a __dict__
to hold the attributes.
I generally just do this:
class Object(object):
pass
a = Object()
a.somefield = somevalue
When I can, I give the Object
class a more meaningful name, depending on what kind of data I'm putting in it.
Some people do a different thing, where they use a sub-class of dict
that allows attribute access to get at the keys. (d.key
instead of d['key']
)
Edit: For the addition to your question, using setattr
is fine. You just can't use setattr
on object()
instances.
params = ['attr1', 'attr2', 'attr3']
for p in params:
setattr(obj.a, p, value)
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 = someobject
obj.a = lambda: None
setattr(obj.a, '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.
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.
The mock
module is basically made for that.
import mock
obj = mock.Mock()
obj.a = 5
You can also use a class object directly; it creates a namespace:
class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')