getattr nested attributes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gregor Horvath

    getattr nested attributes

    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.Att ributeError' Traceback (most recent call last)

    /<ipython consolein <module>()

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

    ???

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



    any help?

    Greg
  • Christian Heimes

    #2
    Re: getattr nested attributes

    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.


    Comment

    • Peter Otten

      #3
      Re: getattr nested attributes

      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.Att ributeError' Traceback (most recent call
      last)
      >
      /<ipython consolein <module>()
      >
      <type 'exceptions.Att ributeError'>: 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(getat tr(B, "a"), "test")
      'test'

      make your own function that loops over the attributes, or spell it
      >>reduce(getatt r, "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

      Comment

      • Gregor Horvath

        #4
        Re: getattr nested attributes

        Peter Otten schrieb:
        make your own function that loops over the attributes, or spell it
        >
        >>>reduce(getat tr, "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.Att ributeError' Traceback (most recent call last)

        /<ipython consolein <module>()

        <type 'exceptions.Att ributeError'>: 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

        Comment

        • Peter Otten

          #5
          Re: getattr nested attributes

          Gregor Horvath wrote:
          Peter Otten schrieb:
          >
          >make your own function that loops over the attributes, or spell it
          >>
          >>>>reduce(geta ttr, "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.Att ributeError' Traceback (most recent call
          last)
          >
          /<ipython consolein <module>()
          >
          <type 'exceptions.Att ributeError'>: 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

          Comment

          • Wojtek Walczak

            #6
            Re: getattr nested attributes

            On Fri, 15 Aug 2008 11:12:04 +0200, 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.Att ributeError' Traceback (most recent call last)
            >
            >/<ipython consolein <module>()
            >
            ><type 'exceptions.Att ributeError'>: type object 'B' has no attribute 'a[0]'
            >
            Seems that I have to use eval ?
            Nope. Always ask getattr for small things and it will like you:
            >>getattr(getat tr(B, 'a')[0], 'test')
            'test'
            >>>
            it works because:
            >>getattr(B, 'a') == B.a
            True
            >>getattr(B, 'a')[0] == B.a[0]
            True
            >>>
            --
            Regards,
            Wojtek Walczak,

            Comment

            • Steven D'Aprano

              #7
              Re: getattr nested attributes

              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(geta ttr, "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.9213471412658 691, 2.8718900680541 992, 2.8756620883941 65]
              >>Timer("grab2( b, 'a[0]')",
              .... "from __main__ import B, grab2; b = B()").repeat()
              [6.1671040058135 986, 5.2739279270172 119, 5.1346590518951 416]
              >>Timer("grab3( b, 'a[0]')",
              .... "from __main__ import B, grab3; b = B()").repeat()
              [33.484487056732 178, 34.526612043380 737, 34.803802013397 217]


              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

              Comment

              • Paul Boddie

                #8
                Re: getattr nested attributes

                On 15 Aug, 10:35, Gregor Horvath <g...@gregor-horvath.comwrot e:
                >
                <type 'exceptions.Att ributeError'>: 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

                Comment

                • Fredrik Lundh

                  #9
                  Re: getattr nested attributes

                  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.Att ributeError' Traceback (most recent call last)
                  getattr fetches a named attribute, it doesn't evaluate random code
                  snippets. please read the manual.

                  </F>

                  Comment

                  Working...