我有一个看起来像这样的函数:
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
。
(请不要告诉我,我不应该尝试这样做,或者重新设计我的代码,或类似的东西 - 这不可能。)
答案 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()