在Python中反向执行函数

在Python中反向执行函数,python,function,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在逻辑上总是可以反转的;即,没有变

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

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

(请不要告诉我我不应该尝试这样做,或者重新设计我的代码,或者诸如此类的事情-这是不可能的。)

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

functions = [
    call_some_function_A,
    call_some_function_B,
#   [...]
    call_some_function_Z,
]
然后使用它按(相反)顺序调用函数

请不要这样做。
如果
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]
如果函数与全局函数在同一文件中定义,请执行以下操作:

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():
    call_some_function_A()
    if whatever:
        call_some_function_B()
        call_some_function_C()
    call_some_function_D()
导入检查
导入ast
原始f=f
source=inspect.getsource(f)
tree=ast.parse(源代码)
#树是一个模块,其主体由1个FunctionDef组成
#body[0]是一个FunctionDef,其body由expr组成
tree.body[0]。body.reverse()
#顶级表达式将被反转
#将修改后的语法树作为模块编译为代码对象并执行它
exec(编译(树,,'exec'))
#f将被覆盖,因为函数名保持不变
#现在f等于:
#def():
#调用一些函数
#如果测试:
#调用一些函数
#调用一些函数
#调用某个函数
f_uuf=f
f=原始的

所以,是的,这个方法好一点。甚至可以递归地反转所有的
主体
s,并实现
..B
..C
的反转,但即使引入最简单的逻辑代码,您也会遇到糟糕的问题。

我将这个小函数拼凑在一起,该函数假定该函数是一个简单的单行语句列表。它使用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()

+我本来打算做那样的事!一个函数列表就是我想要的。干得好。谢谢你的回答!这可能有效,但我无法修改
f
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
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()