在Python中反向执行函数

时间:2014-03-12 22:32:32

标签: python function

我有一个看起来像这样的函数:

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

我希望函数反向执行;也就是说,执行必须如下:

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

f总是这样,在逻辑上可以反转它;即没有变量声明或类似的东西。)

我该如何做到这一点?

我不能只编写一个函数f'来反向调用f中的语句,因为我不想每次f'更新f }被改变了。

我也无法修改f

(请不要告诉我,我不应该尝试这样做,或者重新设计我的代码,或类似的东西 - 这不可能。)

3 个答案:

答案 0 :(得分:9)

如果您的f()完全由这些函数调用组成,则可以将其重新制作为列表:

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

然后使用它以(反向)顺序调用函数。

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

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

答案 1 :(得分:3)

请不要这样做。


如果您的f()完全由这些函数调用组成:

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

...你可以入侵它并获得它引用的所有名称:

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

但你仍需要获得相应的功能。

如果这些功能在某个其他模块或类似的模块中,请执行以下操作:

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

如果函数在与globals相同的文件中定义,请执行以下操作:

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>]

然后您需要做的就是按相反的顺序调用它们:

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

或者,您可以获取函数的源代码,解析它,反转抽象语法树,将其编译回来,执行它......您将拥有相反的函数。

让我们考虑这个例子:

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

所以是的,这个方法好一点。甚至可以递归地反转所有body并实现...B...C的反转,但如果引入最简单的逻辑代码,则将< / em>遇到了不好的问题。

答案 2 :(得分:1)

我把这个小函数混在一起,假设函数是一行语句的简单列表。它使用exec,这是另一种形式的eval,因此很难编译代码,但如果你可以使用评估代码,那么它是:

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()