Shortcutting the function call stack

Arnaud Delobelle arnodel at googlemail.com
Mon Mar 24 19:26:34 EDT 2008


On Mar 24, 10:05 pm, Julien <jpha... at gmail.com> wrote:
> 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?

Of course it's possible ;), with the combination of an exception and a
decorator.  See example below.  However I would seriously doubt the
maintainability of such practices...

# --------- hijack.py ------------
from functools import wraps

class HijackReturn(Exception):
    def __init__(self, val):
        self.val = val

def hijack(f):
    @wraps(f)
    def hijacked(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except HijackReturn, e:
            return e.val
    return hijacked

@hijack
def foo(x):
    x = x + 1
    hijacker(x)
    return x * 2

def hijacker(x):
    if x == 21:
        print "[Oh no, it's going to be 42!]"
        raise HijackReturn(41)

# -------------------------------

marigold:junk arno$ python -i hijack.py
>>> foo(10)
22
>>> foo(20)
[Oh no, it's going to be 42!]
41
>>>

HTH

--
Arnaud




More information about the Python-list mailing list