views:

135

answers:

5

Hi,

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

so 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 FOR LOOP

How would I set the attribute based on the value of p in the example above?

Thanks

+5  A: 

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)
FogleBird
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
Daniel DiPaolo
Oh right, I'll update my answer.
FogleBird
Hi. Thanks for the answer. I've updated my problem above. see the edit. do you know the answer to this?
John
sorry I still want to set it on the object. see update above.
John
The code I wrote does what you described.
FogleBird
+1  A: 

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.

SilentGhost
A: 

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()
evilpie
+1  A: 

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.

Alex Martelli
I like the `Bunch` recipe, but I don't like the lambda hack.
FogleBird
@FogleBird, a style decision, as I mentioned. Some CS experts trained e.g. in Church's lambda calculus are used to thinking of functions (lambdas) as the fundamental type of all data (the integer 23, for example, can be seen as equivalent to `lambda: 23`), so to such experts using `lambda`s for this purpose would presumably feel nothing like "a hack". Personally, I don't like `lambda` _in Python_ very much -- but that's very much an issue of personal taste.
Alex Martelli
A: 

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: http://stackoverflow.com/questions/1285269/why-cant-you-add-attributes-to-object-in-python

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