getattr nested attributes

G

Gregor Horvath

Hi,

class A(object):
test = "test"

class B(object):
a = A()


In [36]: B.a.test
Out[36]: 'test'

In [37]: getattr(B, "a.test")
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'> Traceback (most recent call last)

/<ipython console> in <module>()

<type 'exceptions.AttributeError'>: type object 'B' has no attribute
'a.test'

???

Documentation says B.a.test and getattr(B, "a.test") should be equivalent.

http://docs.python.org/lib/built-in-funcs.html

any help?

Greg
 
C

Christian Heimes

Gregor said:
any help?

I guess you missunderstood the sentence "For example, getattr(x,
'foobar') is equivalent to x.foobar.". getattr(x, "foo.bar") is not
equivalant to x.foo.bar.
 
P

Peter Otten

Gregor said:
Hi,

class A(object):
test = "test"

class B(object):
a = A()


In [36]: B.a.test
Out[36]: 'test'

In [37]: getattr(B, "a.test")
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'> Traceback (most recent call
last)

/<ipython console> in <module>()

<type 'exceptions.AttributeError'>: type object 'B' has no attribute
'a.test'

???

I think that message is pretty clear. B doesn't have an attribute "a.test",
it has an attribute "a" which in turn has an attribute "test". You can
access it by calling getattr() twice,
'test'

make your own function that loops over the attributes, or spell it
'test'

Documentation says B.a.test and getattr(B, "a.test") should be equivalent.

http://docs.python.org/lib/built-in-funcs.html

No, it doesn't.

Peter
 
G

Gregor Horvath

Peter said:
make your own function that loops over the attributes, or spell it

'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)
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'> Traceback (most recent call last)

/<ipython console> in <module>()

<type 'exceptions.AttributeError'>: type object 'B' has no attribute 'a[0]'

Seems that I have to use eval ?
I have a mapping text file (data) which contains such attributes strings
and those attributes should be read.
 
P

Peter Otten

Gregor said:
Peter said:
make your own function that loops over the attributes, or spell it

'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)
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'> Traceback (most recent call
last)

/<ipython console> in <module>()

<type 'exceptions.AttributeError'>: type object 'B' has no attribute
'a[0]'

Like the screwdriver doesn't work with a nail?
Seems that I have to use eval ?
I have a mapping text file (data) which contains such attributes strings
and those attributes should be read.

When you pass data to eval() it becomes code. If you trust the source of
that text file that would be the easiest approach. Otherwise google
for 'safe eval'.

Peter
 
S

Steven D'Aprano

Peter said:
make your own function that loops over the attributes, or spell it

'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")
grab2(B(), "a[0]")
grab3(B(), "a[0]")
<__main__.A object at 0xb7c7948c>


Which is fastest?
.... "from __main__ import B, grab1; b = B()").repeat()
[3.9213471412658691, 2.8718900680541992, 2.875662088394165]
.... "from __main__ import B, grab2; b = B()").repeat()
[6.1671040058135986, 5.2739279270172119, 5.1346590518951416]
.... "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.
 
P

Paul Boddie

<type 'exceptions.AttributeError'>: type object 'B' has no attribute
'a.test'

You have to realise that attributes can have names beyond those
supported by the usual attribute access syntax. For example:

class C: pass

setattr(C, "x.y", 123)
getattr(C, "x.y") # gives 123
setattr(C, "class $$$", 456)
getattr(C, "class $$$") # gives 456

Note that there's no way of using the object.name syntax to access
these attributes, although some proposals have been made to allow it
in some fashion. What you should conclude from this is that the name
argument to setattr and getattr is just a name, not an expression,
even if you can construct names which look like expressions or other
syntactically meaningful fragments of code.
Documentation says B.a.test and getattr(B, "a.test") should be equivalent.

http://docs.python.org/lib/built-in-funcs.html

No, the documentation says that the name must be "the name of one of
the object's attributes", not an expression fragment that if combined
with the name of the object and evaluated would yield an attribute
from some object or other reachable via the original object.

Paul
 
F

Fredrik Lundh

Gregor said:
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)

getattr fetches a named attribute, it doesn't evaluate random code
snippets. please read the manual.

</F>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top