getattr nested attributes

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Aug 15 08:21:58 EDT 2008


On Fri, 15 Aug 2008 11:12:04 +0200, Gregor Horvath wrote:

> Peter Otten schrieb:
> 
>> make your own function that loops over the attributes, or spell it
>> 
>>>>> reduce(getattr, "a.test".split("."), B)
>> 'test'
>> 
>> 
> Thank's, but this does not work for this case:
> 
> class A(object):
>      test = "test"
> 
> class B(object):
>      a = [A(),]
> 
> In [70]: reduce(getattr, "a[0].test".split("."), B)
> 
> Seems that I have to use eval ?

No you don't.


> I have a mapping text file (data) which contains such attributes strings
> and those attributes should be read.

It might help if you showed what those strings were. I can guess two 
likely formats, so here's a few possible solutions.


def grab1(obj, ref):
    # Assume ref looks like "attr index"
    attr, index = ref.split()
    return getattr(obj, attr)[int(index)]


import re
x = re.compile(r'(.*)\[(.*)\]')
def grab2(obj, ref):
    # Assume ref looks like "attr[index]"
    mo = x.match(ref)
    attr = mo.group(1)
    index = int(mo.group(2))
    return getattr(obj, attr)[index]

def grab3(obj, ref):
    # Assume ref looks like "attr[index]"
    return eval("obj." + ref)



Here they are in action:

>>> grab1(B(), "a 0")
<__main__.A object at 0xb7c7948c>
>>> grab2(B(), "a[0]")
<__main__.A object at 0xb7c7948c>
>>> grab3(B(), "a[0]")
<__main__.A object at 0xb7c7948c>


Which is fastest?

>>> from timeit import Timer
>>> Timer("grab1(b, 'a 0')", 
... "from __main__ import B, grab1; b = B()").repeat()
[3.9213471412658691, 2.8718900680541992, 2.875662088394165]
>>> Timer("grab2(b, 'a[0]')", 
... "from __main__ import B, grab2; b = B()").repeat()
[6.1671040058135986, 5.2739279270172119, 5.1346590518951416]
>>> Timer("grab3(b, 'a[0]')", 
... "from __main__ import B, grab3; b = B()").repeat()
[33.484487056732178, 34.526612043380737, 34.803802013397217]


The first version is about twice as fast as the regular expression 
version, which in turn is about six times as fast as the version using 
eval.


-- 
Steven



More information about the Python-list mailing list