getattr() on nested functions?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gabriel Rossetti

    getattr() on nested functions?

    Hello,

    I can't get getattr() to return nested functions, I tried this :
    >>def toto():
    .... def titi():
    .... pass
    .... f = getattr(toto, "titi")
    .... print str(f)
    ....
    >>toto()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in toto
    AttributeError: 'function' object has no attribute 'titi'
    >>>
    I thought that since functions are objects, that I could obtain it's
    nested functions. How come it doesn't work and what can I do to
    fix/replace it? I'm using it in code that is like this :

    def __test(self, action, *args):
    def request(params) :
    pass

    def submit(params, values):
    pass

    def update(params, values):
    pass

    def delete(params):
    pass

    result = getattr(__test, action)(*args)

    return resultToXml(res ult)

    where "action" is a string containing either "request", "submit",
    "update", or "delete". I was using an evel() with this form :

    result = eval(action + "(params, values)")

    but I didn't find that very clean.

    Thank you,
    Gabriel
  • Hrvoje Niksic

    #2
    Re: getattr() on nested functions?

    Gabriel Rossetti <gabriel.rosset ti@arimaz.comwr ites:
    I can't get getattr() to return nested functions, I tried this :
    >
    >>>def toto():
    ... def titi():
    ... pass
    ... f = getattr(toto, "titi")
    ... print str(f)
    ...
    >>>toto()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in toto
    AttributeError: 'function' object has no attribute 'titi'
    >>>>
    >
    I thought that since functions are objects, that I could obtain it's
    nested functions.
    Note that the nested function is created anew each time you call
    toto(), so there's no reason for it to be stored anywhere. What is
    stored is the internal compiled code object used to create the inner
    function, but it's not easy to get to it, nor is it all that useful to
    try. If you really need this, you can explicitly store the inner
    function in the outer one's dict:

    def outer():
    if not hasattr(outer, 'inner'):
    def inner():
    pass
    outer.inner = inner
    f = outer.inner # same as getattr(outer, 'inner')
    print f # same as print str(f)
    >>outer()
    <function inner at 0xb7cfc294>
    >>outer.inner
    <function inner at 0xb7cfc294>
    def __test(self, action, *args):
    def request(params) :
    pass
    def submit(params, values):
    pass
    def update(params, values):
    pass
    def delete(params):
    pass
    result = getattr(__test, action)(*args)
    return resultToXml(res ult)
    >
    where "action" is a string containing either "request", "submit",
    "update", or "delete".
    Use locals()[action](*args).

    Comment

    • Bruno Desthuilliers

      #3
      Re: getattr() on nested functions?

      Gabriel Rossetti a écrit :
      Hello,
      >
      I can't get getattr() to return nested functions,
      Of course. Nested functions are not attributes of their container function.
      I tried this :
      >
      >>def toto():
      ... def titi():
      ... pass
      ... f = getattr(toto, "titi")
      ... print str(f)
      ...
      >>toto()
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 4, in toto
      AttributeError: 'function' object has no attribute 'titi'
      >>>
      >
      I thought that since functions are objects, that I could obtain it's
      nested functions.
      Well, there's probably a very hackish way, but it's not worth the pain.
      The fact that functions are objects doesn't make nested functions
      methods of that object. If what you really want are methods, then you
      can write your own callable:

      class _Test(object):
      def request(self, params):
      pass
      def submit(self, params, values):
      pass
      def update(self, params, values):
      pass
      def delete(self, params):
      pass
      def __call__(self, action, *args):
      return resultToXml(get attr(self, action)(*args))

      _test = _Test()

      But read the remaining before...
      How come it doesn't work and what can I do to
      fix/replace it? I'm using it in code that is like this :
      >
      def __test(self, action, *args):
      def request(params) :
      pass
      def submit(params, values):
      pass
      def update(params, values):
      pass
      def delete(params):
      pass
      result = getattr(__test, action)(*args)
      return resultToXml(res ult)
      >
      where "action" is a string containing either "request", "submit",
      "update", or "delete". I was using an evel() with this form :
      >
      result = eval(action + "(params, values)")
      Wrong use case for eval, as usual.
      but I didn't find that very clean.
      indeed !-)

      locals() is your friend.

      def _test(self, action, *args):
      def request(params) :
      pass
      def submit(params, values):
      pass
      def update(params, values):
      pass
      def delete(params):
      pass
      result = locals()[action](*args)
      return resultToXml(res ult)


      HTH

      Comment

      • Gabriel Rossetti

        #4
        Re: getattr() on nested functions?

        Bruno Desthuilliers wrote:
        Gabriel Rossetti a écrit :
        >Hello,
        >>
        >I can't get getattr() to return nested functions,
        >
        Of course. Nested functions are not attributes of their container
        function.
        Ok
        >
        >I tried this :
        >>
        > >>def toto():
        >... def titi():
        >... pass
        >... f = getattr(toto, "titi")
        >... print str(f)
        >...
        > >>toto()
        >Traceback (most recent call last):
        > File "<stdin>", line 1, in <module>
        > File "<stdin>", line 4, in toto
        >AttributeError : 'function' object has no attribute 'titi'
        > >>>
        >>
        >I thought that since functions are objects, that I could obtain it's
        >nested functions.
        >
        Well, there's probably a very hackish way, but it's not worth the
        pain. The fact that functions are objects doesn't make nested
        functions methods of that object. If what you really want are methods,
        then you can write your own callable:
        >
        class _Test(object):
        def request(self, params):
        pass
        def submit(self, params, values):
        pass
        def update(self, params, values):
        pass
        def delete(self, params):
        pass
        def __call__(self, action, *args):
        return resultToXml(get attr(self, action)(*args))
        >
        _test = _Test()
        >
        Yes, very hackish :-)
        But read the remaining before...
        >
        >How come it doesn't work and what can I do to fix/replace it? I'm
        >using it in code that is like this :
        >>
        >def __test(self, action, *args):
        > def request(params) :
        > pass
        > def submit(params, values):
        > pass
        > def update(params, values):
        > pass
        > def delete(params):
        > pass
        > result = getattr(__test, action)(*args)
        > return resultToXml(res ult)
        >>
        >where "action" is a string containing either "request", "submit",
        >"update", or "delete". I was using an evel() with this form :
        >>
        >result = eval(action + "(params, values)")
        >
        Wrong use case for eval, as usual.
        >
        >but I didn't find that very clean.
        >
        indeed !-)
        >
        locals() is your friend.
        >
        def _test(self, action, *args):
        def request(params) :
        pass
        def submit(params, values):
        pass
        def update(params, values):
        pass
        def delete(params):
        pass
        result = locals()[action](*args)
        return resultToXml(res ult)
        >
        >
        Ok, thanks, that works :-), like I told Gabriel G., I keep on forgetting
        locals() exists :-)

        Comment

        • Terry Reedy

          #5
          Re: getattr() on nested functions?



          Gabriel Rossetti wrote:
          Bruno Desthuilliers wrote:
          >Gabriel Rossetti a écrit :
          >>I thought that since functions are objects, that I could obtain it's
          >>nested functions.
          >>
          >Well, there's probably a very hackish way, but it's not worth the
          >pain.
          What Bruno meant here, I believe, is that there is probably a hackish
          way to get the nested functions, but it indeed would not be worth the pain.
          > The fact that functions are objects doesn't make nested
          >functions methods of that object.
          A def statement is ultimately an assignment statement. The name of the
          nested function is a local variable just like any other local name.
          >If what you really want are methods,
          >then you can write your own callable:
          >>
          >class _Test(object):
          > def request(self, params):
          > pass
          > def submit(self, params, values):
          > pass
          > def update(self, params, values):
          > pass
          > def delete(self, params):
          > pass
          > def __call__(self, action, *args):
          > return resultToXml(get attr(self, action)(*args))
          >>
          >_test = _Test()
          >>
          Yes, very hackish :-)
          No, not at all hackish, but one standard way to do what you want.
          >locals() is your friend.
          >>
          >def _test(self, action, *args):
          > def request(params) :
          > pass
          > def submit(params, values):
          > pass
          > def update(params, values):
          > pass
          > def delete(params):
          > pass
          > result = locals()[action](*args)
          > return resultToXml(res ult)
          >>
          >>
          Ok, thanks, that works :-), like I told Gabriel G., I keep on forgetting
          locals() exists :-)
          Unlike the class approach, this requires recreating the constant
          functions and dict with each call to _test. Quick to write but a bit
          'dirty', in my opinion. Another standard idiom is to set up the
          constants outside the function:

          def request(params) :
          pass
          def submit(params, values):
          pass
          def update(params, values):
          pass
          def delete(params):
          pass
          dispatch = {'request':requ est, 'submit':submit , 'update':update ,
          'delete':delete }

          def _test(self, action, *args):
          return resultToXmo(dis patch[action](*args))

          Terry Jan Reedy


          Comment

          • Gabriel Rossetti

            #6
            Re: getattr() on nested functions?

            Terry Reedy wrote:
            >
            >
            Gabriel Rossetti wrote:
            >Bruno Desthuilliers wrote:
            >>Gabriel Rossetti a écrit :
            >
            >>>I thought that since functions are objects, that I could obtain
            >>>it's nested functions.
            >>>
            >>Well, there's probably a very hackish way, but it's not worth the pain.
            >
            What Bruno meant here, I believe, is that there is probably a hackish
            way to get the nested functions, but it indeed would not be worth the
            pain.
            Yes, I understood that :-)
            >
            The fact that functions are objects doesn't make nested
            >>functions methods of that object.
            >
            A def statement is ultimately an assignment statement. The name of
            the nested function is a local variable just like any other local name.
            >
            Ok
            If what you really want are methods,
            >>then you can write your own callable:
            >>>
            >>class _Test(object):
            >> def request(self, params):
            >> pass
            >> def submit(self, params, values):
            >> pass
            >> def update(self, params, values):
            >> pass
            >> def delete(self, params):
            >> pass
            >> def __call__(self, action, *args):
            >> return resultToXml(get attr(self, action)(*args))
            >>>
            >>_test = _Test()
            >>>
            >Yes, very hackish :-)
            >
            No, not at all hackish, but one standard way to do what you want.
            >
            >>locals() is your friend.
            >>>
            >>def _test(self, action, *args):
            >> def request(params) :
            >> pass
            >> def submit(params, values):
            >> pass
            >> def update(params, values):
            >> pass
            >> def delete(params):
            >> pass
            >> result = locals()[action](*args)
            >> return resultToXml(res ult)
            >>>
            >>>
            >Ok, thanks, that works :-), like I told Gabriel G., I keep on
            >forgetting locals() exists :-)
            >
            Unlike the class approach, this requires recreating the constant
            functions and dict with each call to _test. Quick to write but a bit
            'dirty', in my opinion. Another standard idiom is to set up the
            constants outside the function:
            >
            def request(params) :
            pass
            def submit(params, values):
            pass
            def update(params, values):
            pass
            def delete(params):
            pass
            dispatch = {'request':requ est, 'submit':submit , 'update':update ,
            'delete':delete }
            >
            def _test(self, action, *args):
            return resultToXmo(dis patch[action](*args))
            That's how I had done it originally (before the use of eval()), but in
            this case also, since the functions are still nested, they are
            re-created and so is the dict, so I don' t see a gain from the locals()
            method.

            Comment

            • Bruno Desthuilliers

              #7
              Re: getattr() on nested functions?

              Gabriel Rossetti a écrit :
              Terry Reedy wrote:
              (snip)
              >Unlike the class approach, this requires recreating the constant
              >functions and dict with each call to _test. Quick to write but a bit
              >'dirty', in my opinion. Another standard idiom is to set up the
              >constants outside the function:
              >>
              >def request(params) :
              > pass
              >def submit(params, values):
              > pass
              >def update(params, values):
              > pass
              >def delete(params):
              > pass
              >dispatch = {'request':requ est, 'submit':submit , 'update':update ,
              >'delete':delet e}
              >>
              >def _test(self, action, *args):
              > return resultToXmo(dis patch[action](*args))
              >
              That's how I had done it originally (before the use of eval()), but in
              this case also, since the functions are still nested,
              Uh ??? You probably want to re-read the above code snippet.



              Comment

              • Gabriel Rossetti

                #8
                Re: getattr() on nested functions?

                Bruno Desthuilliers wrote:
                Gabriel Rossetti a écrit :
                >Terry Reedy wrote:
                (snip)
                >>Unlike the class approach, this requires recreating the constant
                >>functions and dict with each call to _test. Quick to write but a
                >>bit 'dirty', in my opinion. Another standard idiom is to set up the
                >>constants outside the function:
                >>>
                >>def request(params) :
                >> pass
                >>def submit(params, values):
                >> pass
                >>def update(params, values):
                >> pass
                >>def delete(params):
                >> pass
                >>dispatch = {'request':requ est, 'submit':submit , 'update':update ,
                >>'delete':dele te}
                >>>
                >>def _test(self, action, *args):
                >> return resultToXmo(dis patch[action](*args))
                >>
                >That's how I had done it originally (before the use of eval()), but
                >in this case also, since the functions are still nested,
                >
                Uh ??? You probably want to re-read the above code snippet.
                >
                Uh...yes, I didn't see the external/parent function was no longer there.
                I prefer to nest mine though because I have several parent functions for
                different tasks, so each child/nested function has a diff.
                implementation, I find that cleaner than having n*4+n top-level
                functions (+ n dicts), e.g. I prefer this :

                def __task1(self, action, *args):
                def request(params) :
                pass
                def submit(params, values):
                pass
                def update(params, values):
                pass
                def delete(params):
                pass
                return resultToXml(loc als()[action](*args))

                def __task2(self, action, *args):
                def request(params) :
                pass
                def submit(params, values):
                pass
                def update(params, values):
                pass
                def delete(params):
                pass
                return resultToXml(loc als()[action](*args))


                over this :

                def task1_request(p arams):
                pass
                def task1_submit(pa rams, values):
                pass
                def task1_update(pa rams, values):
                pass
                def task1_delete(pa rams):
                pass

                def task2_request(p arams):
                pass
                def task2_submit(pa rams, values):
                pass
                def task2_update(pa rams, values):
                pass
                def task2_delete(pa rams):
                pass

                dispatch_task1 = {'request':task 1_request, 'submit':task1_ submit,
                'update':task1_ update, 'delete':task1_ delete}
                dispatch_task2 = {'request':task 2_request, 'submit':task2_ submit,
                'update':task2_ update, 'delete':task2_ delete}

                def _task1(self, action, *args):
                return resultToXml(dis patch_task1[action](*args))

                def _task2(self, action, *args):
                return resultToXml(dis patch_task2[action](*args))


                I could use your callable approach, but like you said it may not be
                worth the trouble.

                Gabriel

                Comment

                • Bruno Desthuilliers

                  #9
                  Re: getattr() on nested functions?

                  Gabriel Rossetti a écrit :
                  Bruno Desthuilliers wrote:
                  >Gabriel Rossetti a écrit :
                  >>Terry Reedy wrote:
                  >(snip)
                  >>>Unlike the class approach, this requires recreating the constant
                  >>>functions and dict with each call to _test. Quick to write but a
                  >>>bit 'dirty', in my opinion. Another standard idiom is to set up the
                  >>>constants outside the function:
                  >>>>
                  >>>def request(params) :
                  >>> pass
                  >>>def submit(params, values):
                  >>> pass
                  >>>def update(params, values):
                  >>> pass
                  >>>def delete(params):
                  >>> pass
                  >>>dispatch = {'request':requ est, 'submit':submit , 'update':update ,
                  >>>'delete':del ete}
                  >>>>
                  >>>def _test(self, action, *args):
                  >>> return resultToXmo(dis patch[action](*args))
                  >>>
                  >>That's how I had done it originally (before the use of eval()), but
                  >>in this case also, since the functions are still nested,
                  >>
                  >Uh ??? You probably want to re-read the above code snippet.
                  >>
                  Uh...yes, I didn't see the external/parent function was no longer there.
                  I prefer to nest mine though because I have several parent functions for
                  different tasks, so each child/nested function has a diff.
                  implementation, I find that cleaner than having n*4+n top-level
                  functions (+ n dicts), e.g. I prefer this :
                  >
                  def __task1(self, action, *args):
                  def request(params) :
                  pass
                  def submit(params, values):
                  pass
                  def update(params, values):
                  pass
                  def delete(params):
                  pass
                  return resultToXml(loc als()[action](*args))
                  >
                  def __task2(self, action, *args):
                  def request(params) :
                  pass
                  def submit(params, values):
                  pass
                  def update(params, values):
                  pass
                  def delete(params):
                  pass
                  return resultToXml(loc als()[action](*args))
                  >
                  >
                  over this :
                  >
                  (snip)
                  >
                  >
                  I could use your callable approach, but like you said it may not be
                  worth the trouble.
                  The "trouble" I was talking about was not with using callable objects,
                  but with trying to hack func.func_code to extract nested functions (if
                  ever possible).

                  But anyway... The point of using callable objects is to avoid going thru
                  the whole "setup" part again and again and again. Now if all your task
                  functions only differ by the dispatch dict, there's at least another
                  ways to avoid this runtime repetition - as well as coding repetition
                  FWIW (warning : untested code):

                  def _make_task(func ):
                  dispatch = func()
                  def _task(action, *args):
                  return resultToXml(dis patch[action](*args))
                  _task.__name__ = _task.func_name = func.__name__
                  return _task

                  @_make_task
                  def _task1():
                  def request(params) :
                  pass
                  def submit(params, values):
                  pass
                  def update(params, values):
                  pass
                  def delete(params):
                  pass
                  return locals()


                  HTH

                  Comment

                  • castironpi

                    #10
                    Re: getattr() on nested functions?

                    On Aug 21, 10:14 am, Bruno Desthuilliers <bruno.
                    42.desthuilli.. .@websiteburo.i nvalidwrote:
                    Gabriel Rossetti a écrit :
                    >
                    >
                    >
                    Bruno Desthuilliers wrote:
                    Gabriel Rossetti a écrit :
                    >Terry Reedy wrote:
                    (snip)
                    >>Unlike the class approach, this requires recreating the constant
                    >>functions and dict with each call to _test.  Quick to write but a
                    >>bit 'dirty', in my opinion.  Another standard idiom is to set up the
                    >>constants outside the function:
                    >
                    >>def request(params) :
                    >>    pass
                    >>def submit(params, values):
                    >>    pass
                    >>def update(params, values):
                    >>    pass
                    >>def delete(params):
                    >>    pass
                    >>dispatch = {'request':requ est, 'submit':submit , 'update':update ,
                    >>'delete':dele te}
                    >
                    >>def _test(self, action, *args):
                    >>    return resultToXmo(dis patch[action](*args))
                    >
                    >That's how I had done it originally (before the use of eval()), but
                    >in this case also, since the functions are still nested,
                    >
                    Uh ??? You probably want to re-read the above code snippet.
                    >
                    Uh...yes, I didn't see the external/parent function was no longer there..
                    I prefer to nest mine though because I have several parent functions for
                    different tasks, so each child/nested function has a diff.
                    implementation, I find that cleaner than having n*4+n top-level
                    functions (+ n dicts), e.g. I prefer this :
                    >
                       def __task1(self, action, *args):
                           def request(params) :
                               pass
                           def submit(params, values):
                               pass
                           def update(params, values):
                               pass
                           def delete(params):
                               pass
                           return resultToXml(loc als()[action](*args))
                    >
                       def __task2(self, action, *args):
                           def request(params) :
                               pass
                           def submit(params, values):
                               pass
                           def update(params, values):
                               pass
                           def delete(params):
                               pass
                           return resultToXml(loc als()[action](*args))
                    >
                    over this :
                    >
                    (snip)
                    >
                    I could use your callable approach, but like you said it may not be
                    worth the trouble.
                    >
                    The "trouble" I was talking about was not with using callable objects,
                    but with trying to hack func.func_code to extract nested functions (if
                    ever possible).
                    >
                    But anyway... The point of using callable objects is to avoid going thru
                    the whole "setup" part again and again and again. Now if all your task
                    functions only differ by the dispatch dict, there's at least another
                    ways to avoid this runtime repetition - as well as coding repetition
                    FWIW (warning : untested code):
                    >
                    def _make_task(func ):
                         dispatch = func()
                         def _task(action, *args):
                             return resultToXml(dis patch[action](*args))
                         _task.__name__ = _task.func_name = func.__name__
                        return _task
                    >
                    @_make_task
                    def _task1():
                         def request(params) :
                             pass
                         def submit(params, values):
                             pass
                         def update(params, values):
                             pass
                         def delete(params):
                             pass
                         return locals()
                    >
                    HTH
                    Here's more ideas:

                    Use a wrapper to give the function access to itself as an object:

                    @auto
                    def f( self, arg ):
                    assert self== f

                    In your original example:

                    @auto
                    def toto( toto ):
                    def titi():
                    pass
                    f = getattr(toto, "titi")
                    print str(f)

                    Should work, untested. Another is to use a wrapper to participate
                    functions in a dictionary:

                    @entry( 'a' )
                    def a( arg ):
                    a_stuff( )

                    @entry( 'b' )
                    def b( arg ):
                    b_stuff

                    You could even make 'entry' a class instance, so you can specialize
                    and vary it in other cases, untested.

                    Last one is just use a class, untested:

                    class __Test:
                    def __test(self, action, *args):
                    result = getattr(self, action)(*args)
                    return resultToXml(res ult)

                    def request(self,pa rams):
                    pass

                    def submit(self,par ams, values):
                    pass

                    def update(self,par ams, values):
                    pass

                    def delete(self,par ams):
                    pass

                    Keep us posted which one works for you.

                    Comment

                    Working...