Shortcutting the function call stack

Julien jphalip at gmail.com
Mon Mar 24 18:05:38 EDT 2008


Hi all, and thanks a lot for your answers!

I'll try to explain a bit more what I'm after, and hopefully that will
be clearer. In fact, what I'm trying to do is to "hijack" (I'm making
up the term) a function:

def hijacker(arg):
    if I_feel_its_necessary:
        hijack_caller_function_and_make_it_return(1)

def my_function1(arg):
    hijacker(something)
    ... # Continue as normal
    return 2

def my_function2(arg):
    ... # Maybe do some processing here
    hijacker(whatever)
    ... # Continue as normal
    return 3


I have some long functions like my_function1 and my_function2 which
I'd like to alter, but I want to keep the alterations as little as as
possible. I'd like the extra behaviour to be handled by 'hijacker' and
let it decide what the caller function should return. Just adding a
call to 'hijacker' in all of these functions would be ideal for me
because that would be quick to modify them and also easier to
maintain, I believe.

If 'hijacker' thinks it's necessary, it would force the caller
function to return a certain
value, otherwise it would let the caller function do its normal
business.

For while I thought I'd make hijacker a decorator:

@hijacker
def my_function(request):
....

But that wouldn't work, since some functions need to do some
processing before calling the hijacker. Yet, I think a decorator is
systematically called before the function itself so no prior
processing can be done by the function...

Any idea on how to do that, if that's even possible?

Thanks!

Julien

On Mar 25, 2:06 am, castiro... at gmail.com wrote:
> On Mar 24, 9:48 am, Jason <tenax.racc... at gmail.com> wrote:
>
>
>
> > On Mar 24, 5:21 am, Julien <jpha... at gmail.com> wrote:
>
> > > Hello all,
>
> > > I would like to do something like:
>
> > > def called(arg)
> > >     if arg==True:
> > >         !!magic!!caller.return 1
>
> > > def caller(arg)
> > >     called(arg)
> > >     return 2
>
> > > Here, the fake !!!magic!!! represents a statement (which I ignore)
> > > that would make the caller function return a value different from what
> > > it'd return normally.
>
> > > For example, caller(True) would return 1, and caller(False) would
> > > return 2. The reason I want that is because I don't want the caller
> > > function to know what's going on in the called function, and be
> > > shortcut if the called function think it's necessary.
>
> > > Would you know if that's possible, and if so, how?
>
> > > I've done a bit of research and I think I've found some good pointers,
> > > in particular using the 'inspect' library:
>
> > > import inspect
>
> > > def called(arg)
> > >     if arg==True:
> > >         caller_frame = inspect.stack()[1]
> > >         ...
>
> > > Here 'caller_frame' contains the frame of the caller function. Now,
> > > how can I make that frame return a particular value?
>
> > > By the way, I'm not really interested in 'called' throwing an
> > > exception and 'caller' catching it. In fact, I want things to remain
> > > completely transparent for 'caller'.
>
> > > Hope that was clear... :/
>
> > > Thanks!
>
> > > Julien
>
> > As Steven wrote, it's not very clear.  If we knew the intent of this,
> > we could perhaps point you to a more useful, maintainable technique.
> > We don't know why you're trying to circumvent the programming language
> > in this case.  Any solution that works as you described will probably
> > be unportable between the different Pythons (CPython, Jython,
> > IronPython, etc).
>
> > Please note that the following code should work, but I've only run it
> > through the interpreter in my brain.  My brain's interpreter is full
> > of Heisenbugs, so you may need to adjust a few things.  Here's my
> > thoughts:
>
> > Given:
> >     def First( arg ):
> >         Second( arg )
> >         return 5
>
> > 1)  If you can modify both functions, change the first function to
> > return a value in certain circumstances:
> >     def AltFirst( arg ):
> >         value = Second( arg )
> >         if value is not None:  return value
> >         return 5
>
> > 2)  Raise an exception in Second, and catch that exception above
> > First:
>
> > class SecondExcept(Exception):
> >     def __init__(self, value):
> >         Exception.__init__(self, 'Spam!')
> >         self.value = value
>
> > def Second(arg):
> >     if arg == my_conditional_value:
> >         raise SecondExcept( 5 )
>
> > # The following could even be put in your own function,
> > # or in a wrapper or decorator for the First function.
> > try:
> >     myvalue = First( 'Vikings!' )
> > except SecondExcept, exc:
> >     myvalue = exc.value
>
> > When you need to use an exceptional pathway, use an exception.  They
> > aren't just for reporting errors.
>
> Exceptions are a control tool.  There was a 'goto using Exceptions'
> once in the manuals.  I don't see a problem with a local control-flow
> object.  It would appease a number of requests I've read.
>
> for x:
>   for y:
>     control.break( 2 )
>
> if a:
>   if b:
>     control.fail( 2 )
>
> so no need to reduplicate:
>
>   else:
>     thing()
> else:
>   thing()
>
> if a:
>   if b:
>     control.mostrecenttest( 0 )
>
> def f():
>   def g():
>     control.return( 2 )( "early" )
>
> Something tells me generators could solve the problem, but I may be
> enamored, so it's a separate post.




More information about the Python-list mailing list