How to dynamically compose and access class attributes in Python? [duplicate]

You can use getattr() to access a property when you don't know its name until runtime:

obj = myobject()
i = 7
date7 = getattr(obj, 'date%d' % i) # same as obj.date7

If you keep your numbered classes in a module called foo, you can use getattr() again to access them by number.

foo.py:
  class Class1: pass
  class Class2: pass
  [ etc ]


bar.py:
  import foo
  i = 3
  someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3
  obj = someClass() # someClass is a pointer to foo.Class3
  # short version:
  obj = getattr(foo, "Class%d" % i)()

Having said all that, you really should avoid this sort of thing because you will never be able to find out where these numbered properties and classes are being used except by reading through your entire codebase. You are better off putting everything in a dictionary.


For the first case, you should be able to do:

getattr(myobject, 'date%s' % i)

For the second case, you can do:

myobject = locals()['MyClass%s' % k]()

However, the fact that you need to do this in the first place can be a sign that you're approaching the problem in a very non-Pythonic way.


OK, well... It seems like this needs a bit of work. Firstly, for your date* things, they should be perhaps stored as a dict of attributes. eg, myobj.dates[1], so on.

For the classes, it sounds like you want polymorphism. All of your MyClass* classes should have a common ancestor. The ancestor's __new__ method should figure out which of its children to instantiate.

One way for the parent to know what to make is to keep a dict of the children. There are ways that the parent class doesn't need to enumerate its children by searching for all of its subclasses but it's a bit more complex to implement. See here for more info on how you might take that approach. Read the comments especially, they expand on it.

class Parent(object):
    _children = {
      1: MyClass1,
      2: MyClass2,
    }

    def __new__(k):
        return object.__new__(Parent._children[k])

class MyClass1(Parent):
    def __init__(self):
        self.foo = 1

class MyClass2(Parent):
    def __init__(self):
        self.foo = 2

bar = Parent(1)
print bar.foo # 1
baz = Parent(2)
print bar.foo # 2

Thirdly, you really should rethink your variable naming. Don't use numbers to enumerate your variables, instead give them meaningful names. i and k are bad to use as they are by convention reserved for loop indexes.

A sample of your existing code would be very helpful in improving it.