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?
For details on why it doesn't work, see Can't set attributes on instance of "object" class.
asked May 13, 2010 at 14:34
4
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]
answered May 13, 2010 at 14:41
FogleBirdFogleBird
71.5k25 gold badges121 silver badges131 bronze badges
7
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.
answered May 13, 2010 at 14:49
Alex MartelliAlex Martelli
823k163 gold badges1202 silver badges1379 bronze badges
14
The mock
module is basically made for that.
import mock
obj = mock.Mock[]
obj.a = 5
answered Feb 9, 2017 at 15:47
DunatotatosDunatotatos
1,60614 silver badges24 bronze badges
3
You can also use a class object directly; it creates a namespace:
class a: pass
a.somefield1 = 'somevalue1'
setattr[a, 'somefield2', 'somevalue2']
answered Jan 5, 2018 at 23:44
ErnestoErnesto
9008 silver badges12 bronze badges
3
There are a few ways to reach this goal. Basically you need an object which is extendable.
obj.a = type['Test', [object,], {}]
obj.a.b = 'fun'
obj.b = lambda:None
class Test:
pass
obj.c = Test[]
mbarkhau
7,9404 gold badges29 silver badges34 bronze badges
answered May 13, 2010 at 14:48
evilpieevilpie
2,62019 silver badges21 bronze badges
1
Now you can do [not sure if it's the same answer as evilpie]:
MyObject = type['MyObject', [object,], {}]
obj = MyObject[]
obj.value = 42
answered Sep 13, 2013 at 0:32
andreabediniandreabedini
1,2751 gold badge12 silver badges20 bronze badges
1
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']
answered Jul 23, 2015 at 20:49
neldorneldor
2312 silver badges2 bronze badges
4
as docs say:
Note:
object
does not have a__dict__
, so you can’t assign arbitrary attributes to an instance of theobject
class.
You could just use dummy-class instance.
answered May 13, 2010 at 14:43
SilentGhostSilentGhost
293k64 gold badges301 silver badges291 bronze badges
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
answered Aug 27, 2015 at 20:34
Robpol86Robpol86
1,54520 silver badges16 bronze badges
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']
answered Nov 19, 2018 at 21:59
HarlemSquirrelHarlemSquirrel
7,6264 gold badges32 silver badges33 bronze badges
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?
answered May 13, 2010 at 14:52
jnevesjneves
1,0147 silver badges7 bronze badges
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
answered Aug 21, 2020 at 15:58
PjlPjl
1,74418 silver badges21 bronze badges
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].
answered Mar 2, 2016 at 2:17
Paul WhippPaul Whipp
15.3k4 gold badges40 silver badges52 bronze badges
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.
answered Apr 25 at 12:50
WeiloryWeilory
2,01811 silver badges25 bronze badges
This works just fine:
exec["obj.a."+p]
If you want to set the attribute to some value, do this:
exec["obj.a."+p+"=[the value here]"]
For the value to be a string you will have to use these \" instead of quotation marks unless you have the value stored in a variable.
answered Jul 6 at 17:04
di = {}
for x in range[20]:
name = '_id%s' % x
di[name] = type[name, [object], {}]
setattr[di[name], "attr", "value"]
answered Dec 27, 2013 at 19:41
lmoktolmokto
1319 bronze badges
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]
leota
1,5582 gold badges12 silver badges33 bronze badges
answered May 13, 2016 at 17:22
2