Shortest way of creating an object with arbitrary attributes in Python?

Viewed 24477

Hey, I just started wondering about this as I came upon a code that expected an object with a certain set of attributes (but with no specification of what type this object should be).

One solution would be to create a new class that has the attributes the code expects, but as I call other code that also needs objects with (other) attributes, I'd have to create more and more classes.

A shorter solution is to create a generic class, and then set the attributes on instances of it (for those who thought of using an instance of object instead of creating a new class, that won't work since object instances don't allow new attributes).

The last, shortest solution I came up with was to create a class with a constructor that takes keyword arguments, just like the dict constructor, and then sets them as attributes:

class data:
    def __init__(self, **kw):
        for name in kw:
            setattr(self, name, kw[name])

options = data(do_good_stuff=True, do_bad_stuff=False)

But I can't help feeling like I've missed something obvious... Isn't there a built-in way to do this (preferably supported in Python 2.5)?

11 Answers

The original code can be streamlined a little by using __dict__:

In [1]: class data:
   ...:     def __init__(self, **kwargs):
   ...:         self.__dict__.update(kwargs)
   ...: 

In [2]: d = data(foo=1, bar=2)

In [3]: d.foo
Out[3]: 1

In [4]: d.bar
Out[4]: 2

In Python 3.3 and greater, this syntax is made available by the types.SimpleNamespace class.

Use collections.namedtuple.

It works well.

from collections import namedtuple
Data = namedtuple( 'Data', [ 'do_good_stuff', 'do_bad_stuff' ] )
options = Data( True, False )

This is the shortest way I know

>>> obj = type("myobj",(object,),dict(foo=1,bar=2))
>>> obj.foo
1
>>> obj.bar
2
>>> 

using dict instead of {} insures your attribute names are valid

>>> obj = type("myobj",(object,),{"foo-attr":1,"bar-attr":2})
>>> obj.foo-attr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'myobj' has no attribute 'foo'
>>>

This works in 2.5, 2.6, and 3.1:

class Struct(object):
    pass

something = Struct()
something.awesome = abs

result = something.awesome(-42)

EDIT: I thought maybe giving the source would help out as well. http://docs.python.org/tutorial/classes.html#odds-and-ends

EDIT: Added assignment to result, as I was using the interactive interpreters to verify, and you might not be.

If I understand your question correctly, you need records. Python classes may be used this way, which is what you do.

I believe the most pythonic way of dealing with "records" is simply... dictionaries! A class is a sort of dictionary on steroids.

Your class example data is essentially a way of converting a dictionary into a class.

(On a side note, I would rather use self.__setattr__(name, kw[name]).)

This is typically something you would use a dict for, not making a class at all.

Related