3

I have a function that looks something like this:

def f():
  call_some_function_A()
  call_some_function_B()
  [...]
  call_some_function_Z()

I'd like the function to be executed in reverse; that is, the execution must look like:

def f'():
  call_some_function_Z()
  [...]
  call_some_function_B()
  call_some_function_A()

(f will always be such that it is logically possible to reverse it; i.e. there are no variable declarations or anything like that).

How can I accomplish this?

I can't just write a function f' that calls the statements from f in reverse, because I don't want to have to update f' every time f is changed.

I also can't modify f.

(Please don't tell me that I shouldn't try to do that, or redesign my code, or anything like that- it's not a possibility.)

3 Answers 3

11

If your f() consists entirely of these function calls, you can remake it into a list:

functions = [
    call_some_function_A,
    call_some_function_B,
#   [...]
    call_some_function_Z,
]

And then use it to call the functions in (reversed) order.

def f():
    for func in functions:
        func()

def f_():
    for func in reversed(functions):
        func()
Sign up to request clarification or add additional context in comments.

2 Comments

+1 I was going to do something like that! A list of functions is what I was headed for. Nice job.
Thanks for the answer! That could work, but I can't modify f.
4

Please don't do this.


If your f() consists entirely of these function calls:

def f():
    call_some_function_A()
    call_some_function_B()
#   [...]
    call_some_function_Z()

...you can hack into it and get all the names it references:

names = f.__code__.co_names
# ('call_some_function_A', 'call_some_function_B', 'call_some_function_Z')

But you still need to get the corresponding functions.

If the functions are in some other module or anything similar, just do this:

functions = [getattr(some_module, name) for name in names]

If the functions are defined in the same file as globals, do this:

functions = [globals()[name] for name in names]
# [<function __main__.call_some_function_A>, <function __main__.call_some_function_B>, <function __main__.call_some_function_Z>]

Then all you need to do is call them in reverse order:

def f_():
    for func in reversed(functions):
        func()

Alternatively, you can obtain the function's source code, parse it, reverse the the abstract syntax tree, compile it back, execute it... and you will have yourself the reversed function.

Let's consider this example:

def f():
    call_some_function_A()
    if whatever:
        call_some_function_B()
        call_some_function_C()
    call_some_function_D()
import inspect
import ast

original_f = f

source = inspect.getsource(f)
tree = ast.parse(source)
# tree is a Module, with body consisting of 1 FunctionDef
# tree.body[0] is a FunctionDef, with body consisting of Exprs
tree.body[0].body.reverse() 
# top level expressions will be reversed

# compile the modified syntax tree to a code object as a module and execute it
exec(compile(tree, '<unknown>', 'exec'))
# f will be overwritten because the function name stays the same

# now f will be equivalent to:
#   def f():
#       call_some_function_D()
#       if test:
#           call_some_function_B()
#           call_some_function_C()
#       call_some_function_A()

f_ = f
f = original_f

So yes, this method is a bit better. It is even possible to recursively reverse all the bodys and achieve the reversal of ...B and ...C as well, but if even the simplest logic code is introduced, you will run into bad problems.

Comments

1

I hacked together this small function which assumes that the function is a simple list of one line statements. It uses exec which is another form of eval and so it makes it hard to compile the code but if you can live with evaluated code here it is:

import inspect

# sample function that will be reversed
def f(): 
  print "first statement"
  print "2nd statement"
  print "last statement"

def makeReversedFunctionSrc(newName, f):
    src = inspect.getsource(f)
    srcLines = src.split("\n")
    srcLines = srcLines[1:] # get rid of the old function definition
    srcLines.reverse() # reverse function body
    # hack together new function definition with reversed lines
    newSrc = "def " + newName + "():\n"
    for line in srcLines:
        if line.strip() != "":
            newSrc += line + "\n"
    return newSrc

# get the code as a string
reverseCode = makeReversedFunctionSrc("reversedF", f)
# execute the string as if it was python (I heard thats evil as in eval)
exec(reverseCode)

# now lets call our new function
reversedF()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.