281

I have a class like the following:

class User:
    def __init__(self):
        self.data = []
        self.other_data = []

    def doSomething(self, source):
        // if source = 'other_data' how to access self.other_data

I want to pass a string for the source variable in doSomething and access the class member of the same name.

I have tried getattr which only works on functions (from what I can tell) as well as having User extend dict and using self.__getitem__, but that doesn't work either. What is the best way to do this?

4 Answers4

383

x = getattr(self, source) will work just perfectly if source names ANY attribute of self, including the other_data in your example.

serv-inc
  • 35,772
  • 9
  • 166
  • 188
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 9
    (realizing this is an old thread). I was confused/always forget this because of dicts. If I want to get a value from a dict, I can say: myDict.get('keyy'), so I would expect attributes to work the same way: myObject.getattr('attr_name'). But instead they take the object as a first argument...ok to do, but the apparent inconsistency is why I had trouble. – Robert Lugg Nov 20 '14 at 22:53
264

A picture's worth a thousand words:

>>> class c:
        pass
o = c()
>>> setattr(o, "foo", "bar")
>>> o.foo
'bar'
>>> getattr(o, "foo")
'bar'
Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
  • 8
    I like this answer in particular because it illustrates, simply, that the getattr() function works outside class methods as well. – Eric Dec 08 '11 at 04:49
109
  • getattr(x, 'y') is equivalent to x.y
  • setattr(x, 'y', v) is equivalent to x.y = v
  • delattr(x, 'y') is equivalent to del x.y
Yas
  • 4,957
  • 2
  • 41
  • 24
5

Extending Alex's answer slightly:

class User:
    def __init__(self):
        self.data = [1,2,3]
        self.other_data = [4,5,6]
    def doSomething(self, source):
        dataSource = getattr(self,source)
        return dataSource

A = User()
print A.doSomething("data")
print A.doSomething("other_data")

will yield:

[1, 2, 3]
[4, 5, 6]

However, personally I don't think that's great style - getattr will let you access any attribute of the instance, including things like the doSomething method itself, or even the __dict__ of the instance. I would suggest that instead you implement a dictionary of data sources, like so:

class User:
    def __init__(self):

        self.data_sources = {
            "data": [1,2,3],
            "other_data":[4,5,6],
        }

    def doSomething(self, source):
        dataSource = self.data_sources[source]
        return dataSource

A = User()

print A.doSomething("data")
print A.doSomething("other_data")

again yielding:

[1, 2, 3]
[4, 5, 6]
Markus
  • 3,447
  • 3
  • 24
  • 26
  • I didn't explain properly... my apologies. I am able to get the data via the string. However, I am having problems setting the data using the above methods. Specifically I have tried getattr(self, "other_data") = [1, 2, 3] as well as self.__setitem__("other_data", [1, 2, 3]) – sberry Jul 22 '09 at 20:39
  • 1
    @sberry2A, `getattr()` is only for getting, `setattr()` is for setting. You can't assign to the return value from `getattr()`. – smci Aug 16 '11 at 23:44