2

Based on

In [65]: %paste
class Thing(object):
    def __init__(self, obj):
        self.legs = 4
        self.obj = obj
    def length(self):
        return 6

class Thing2(object):
    def __init__(self):
        self.arms = 2

## -- End pasted text --

In [66]: t = Thing2()

In [67]: x = Thing(t)

In [68]: x.obj.arms
Out[68]: 2

In [69]: %paste
def set_session_attribute(obj, attribute):
    if attribute.endswith('()'):
        attribute = attribute.replace('()', '')
        return getattr(obj, attribute)()
    else:
        return getattr(obj, attribute)

## -- End pasted text --

In [70]: x = set_session_attribute(x, 'obj.arms')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-70-f8cbad3c39e5> in <module>()
----> 1 x = set_session_attribute(x, 'obj.arms')

<ipython-input-69-65b6efa81583> in set_session_attribute(obj, attribute)
      4         return getattr(obj, attribute)()
      5     else:
----> 6         return getattr(obj, attribute)

AttributeError: 'Thing' object has no attribute 'obj.arms'

How can I use getattr to find arms of the t object in one line? Thank you

class Thing(object):
    def __init__(self, obj):
        self.legs = 4
        self.obj = obj

    def length(self):
        return 6

class Other(object):
    def __init__(self):
        self.arms = 2

    def length(self):
        return 5


def set_session_attribute(obj, attribute):
    attrs = attribute.split('.')
    for attribute in attrs:
        if attribute.endswith('()'):
            attribute = attribute.replace('()', '')
            obj = getattr(obj, attribute)()
        else:
            obj = getattr(obj, attribute)
    return obj

a = Other() # other has attr or function too
b = Thing(a) # thing has other obj, attr, and its own function

"""
In [80]: b.obj.length()
Out[80]: 5

In [81]: b.obj.arms
Out[81]: 2

In [83]: b.length()
Out[83]: 6

In [84]: b.legs
Out[84]: 4
"""

g = set_session_attribute(b, 'obj.length()')
h = set_session_attribute(b, 'obj.arms')
i = set_session_attribute(b, 'length()')
j = set_session_attribute(b, 'legs')
assert g == 5
assert h == 2
assert i == 6
assert j == 4
codyc4321
  • 9,014
  • 22
  • 92
  • 165
  • `Thing` object's have an attribute named `'arms'`, not `'obj.arms'`. – martineau Apr 04 '16 at 20:14
  • `obj.arms` isn't a single attribute, it is an attribute within an attribute. – o11c Apr 04 '16 at 20:16
  • 1
    What's this `set_session_attribute` function for? What formats is it expected to handle? You've asked a question about getting it to handle `x.foo()` and a question about getting it to handle `x.foo.bar` now; if it has to handle stuff like `x.foo[3]('asdf').bar` or `x.foo+3`, we might as well get it out of the way now. – user2357112 Apr 04 '16 at 20:17
  • Yes I'd like it to handle any type of attribute on an object passed and set them elsewhere, so far I've seen a regular attribute, an attribute of an object that's a foreign key, and a function on the object – codyc4321 Apr 04 '16 at 20:21
  • 1
    so you are trying to write [a function to `eval`uate arbitrary python expression](https://docs.python.org/3/library/functions.html#eval)? – Tadhg McDonald-Jensen Apr 04 '16 at 20:24

3 Answers3

1

x.obj.arms would be equivalent to getattr(getattr(x, 'obj'), 'arms').

>>> x = Thing(Thing2())
>>> x.obj.arms
2
>>> getattr(getattr(x, 'obj'), 'arms')
2

Or, starting from an instance of Thing2, you'd just write

>>> t = Thing2()
>>> getattr(t, 'arms')
2
timgeb
  • 76,762
  • 20
  • 123
  • 145
1

You can try this:

    def set_session_attribute(obj, attribute):
        if attribute.endswith('()'):
            attribute = attribute.replace('()', '')
        attrs = attribute.split('.')
        for attr in attrs:
            obj = getattr(obj, attr)
        return obj
user2195058
  • 887
  • 7
  • 10
1

Try this:

class Thing(object):
    def __init__(self, obj):
        self.legs = 4
        self.obj = obj
    def length(self):
        return 6

class Thing2(object):
    def __init__(self):
        self.arms = 2

def recursiveAttr(obj, attribute):
    attributeHierarchy = attribute.split('.')
    for attr in attributeHierarchy:
        obj = getattr(obj, attr)
    return obj

def get_session_attribute(obj, attribute):
    if attribute.endswith('()'):
        attribute = attribute.replace('()', '')
        return recursiveAttr(obj, attribute)()
    else:
        return recursiveAttr(obj, attribute)

t = Thing2()
x = Thing(t)
print get_session_attribute(x, 'obj.arms')
Pedro
  • 409
  • 2
  • 7