getattr() on nested functions?

castironpi castironpi at gmail.com
Thu Aug 21 13:50:11 EDT 2008


On Aug 21, 10:14 am, Bruno Desthuilliers <bruno.
42.desthuilli... at websiteburo.invalid> wrote:
> 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':request, 'submit':submit, 'update':update,
> >>>> 'delete':delete}
>
> >>>> def _test(self, action, *args):
> >>>>     return resultToXmo(dispatch[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(locals()[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(locals()[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(dispatch[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(result)

        def request(self,params):
            pass

        def submit(self,params, values):
            pass

        def update(self,params, values):
            pass

        def delete(self,params):
            pass

Keep us posted which one works for you.




More information about the Python-list mailing list