getattr nested attributes

Discussion in 'Python' started by Gregor Horvath, Aug 15, 2008.

  1. 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
     
    Gregor Horvath, Aug 15, 2008
    #1
    1. Advertising

  2. Gregor Horvath wrote:
    > 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.
     
    Christian Heimes, Aug 15, 2008
    #2
    1. Advertising

  3. Gregor Horvath

    Peter Otten Guest

    Gregor Horvath wrote:

    > 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,

    >>> getattr(getattr(B, "a"), "test")

    'test'

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

    >>> reduce(getattr, "a.test".split("."), B)

    '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
     
    Peter Otten, Aug 15, 2008
    #3
  4. 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)
    ---------------------------------------------------------------------------
    <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.

    --
    Greg
     
    Gregor Horvath, Aug 15, 2008
    #4
  5. Gregor Horvath

    Peter Otten Guest

    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)
    > ---------------------------------------------------------------------------
    > <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
     
    Peter Otten, Aug 15, 2008
    #5
  6. 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
     
    Steven D'Aprano, Aug 15, 2008
    #6
  7. Gregor Horvath

    Paul Boddie Guest

    On 15 Aug, 10:35, Gregor Horvath <> wrote:
    >
    > <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
     
    Paul Boddie, Aug 15, 2008
    #7
  8. Gregor Horvath wrote:

    > 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)


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

    </F>
     
    Fredrik Lundh, Aug 15, 2008
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. daishi
    Replies:
    0
    Views:
    586
    daishi
    Jul 25, 2003
  2. Srikanth Mandava

    getattr

    Srikanth Mandava, Feb 19, 2004, in forum: Python
    Replies:
    2
    Views:
    476
    Peter Hansen
    Feb 19, 2004
  3. Brian Roberts

    Confused about hasattr/getattr/namespaces

    Brian Roberts, Feb 29, 2004, in forum: Python
    Replies:
    2
    Views:
    318
    Bob Ippolito
    Feb 29, 2004
  4. SimonVC

    getattr() in default namespace.

    SimonVC, Apr 8, 2004, in forum: Python
    Replies:
    3
    Views:
    938
    SimonVC
    Apr 9, 2004
  5. Gabriel Rossetti

    Re: getattr() on nested functions?

    Gabriel Rossetti, Aug 21, 2008, in forum: Python
    Replies:
    4
    Views:
    357
    castironpi
    Aug 21, 2008
Loading...

Share This Page