我如何在运行时修改/重新编译已经定义的函数

时间:2018-10-19 00:02:04

标签: python python-3.x

首先,是的,我知道这不是好习惯。这只是一个实验,而不是实际的计划代码。

问题: 我有一个功能

def foo:
    print("hi there")

def foo2:
    #Any stack/recompiling manipulation goes here

def main:
    foo2()
    foo()

在运行时是否可以通过foo2()处理foo()的定义?

我一直在努力尝试更改帧中的变量,但是大多数都是只读的(保存f_local)。

2 个答案:

答案 0 :(得分:2)

如果您对python中的字节码级别的东西感兴趣,请允许我介绍discompileCodeType

请勿在生产代码中执行任何此操作

您可以将compile python代码(作为字符串)放入Code对象,然后可以覆盖函数的__code__属性

def foo():
    print('hi there')
code_stuff = compile("print('this is hacked in')", "dummy file", "exec")
foo.__code__ = code_stuff
foo() #prints "this is hacked in"

如果您要修改多于无输入无输出功能,请查看types.CodeType构造函数:

>>> import types
>>> help(types.CodeType)
Help on class code in module builtins:

class code(object)
 |  code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
 |        constants, names, varnames, filename, name, firstlineno,
 |        lnotab[, freevars[, cellvars]])
 |  
 |  Create a code object.  Not for the faint of heart.
 |  ...

与编写汇编代码很像,这涉及到存在段错误,使python解释器崩溃或更糟的风险。您知道唯一的文档是Not for the faint of heart.时,开发人员并不打算直接使用它。

如果要查看实际执行的字节码,可以使用dis。这是“拆卸”的缩写

def foo():
    print('hi there')

import dis
dis.dis(foo)

这很有趣,看看python代码实际上是如何执行的。

我不确定您要对堆栈进行什么操作,但我可以肯定它是什么,python的开发人员已确保这并不容易,因为这不是您应该在python中接触的东西。这些类型仅出于自省的原因而存在于python中(例如,通过检查函数的调用签名来查看函数的参数在运行时是什么)

答案 1 :(得分:1)

如果您想操纵foo的定义,可以像使用其他任何全局变量一样使用foo语句和{{1 }}:

global

=放在def foo(): print('hi there') def foo2(): global foo def replacement_foo(): print('hi from over here') foo = replacement_foo def main(): foo2() foo() main() 内而不是定义def foo(): ...然后进行分配也很安全,但这是officially not permitted,即使实现未强制执行。


在注释中,您似乎对以某种方式操纵堆栈中的foo2非常感兴趣。 replacement_foo的定义不在堆栈上,并且在执行foo期间堆栈上没有对foo的调用,因此堆栈是错误的查找位置。 / p>

此外,Python的大多数堆栈检查都是只读的。即使您要重新分配函数的代码对象,它也不会更改已在堆栈中的调用的代码。您不能更改foo的代码对象以使其不调用foo(尽管您可以更改main的代码对象,并且在{{1} }调用foo)。