Python 如何在运行时修改/重新编译已定义的函数
首先,是的,我知道这不是一个好的做法。这只是一个实验,不是实际的计划代码 问题是: 我有一个函数Python 如何在运行时修改/重新编译已定义的函数,python,python-3.x,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)。如果您想操作foo的定义,可
def foo:
print("hi there")
def foo2:
#Any stack/recompiling manipulation goes here
def main:
foo2()
foo()
有没有办法在运行时从foo2()操作foo()的定义
我一直在尝试更改帧中的变量,但大多数都是只读的(保存f_local)。如果您想操作
foo
的定义,可以直接重新定义foo
,就像您分配任何其他全局变量一样,使用全局
语句和=
:
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()
在foo2
中定义def foo():…
而不是定义replacement\u foo
然后分配,这可能也是安全的,但即使实现没有强制执行它
在注释中,您似乎对通过堆栈操纵
foo
非常感兴趣。foo
的定义不在堆栈上,在执行foo
期间,堆栈上没有对foo
的调用,因此堆栈是错误的查找位置
此外,Python的大多数堆栈检查都是只读的。即使要重新分配函数的代码对象,它也不会更改堆栈上已有的调用代码。您不能更改
main
的代码对象,使其不调用foo
(尽管您可以更改foo
的代码对象,这将在main
调用foo
时生效)。如果要操作foo
的定义,重新定义foo
非常简单,就像分配任何其他全局变量一样,使用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()
在foo2
中定义def foo():…
而不是定义replacement\u foo
然后分配,这可能也是安全的,但即使实现没有强制执行它
在注释中,您似乎对通过堆栈操纵
foo
非常感兴趣。foo
的定义不在堆栈上,在执行foo
期间,堆栈上没有对foo
的调用,因此堆栈是错误的查找位置
此外,Python的大多数堆栈检查都是只读的。即使要重新分配函数的代码对象,它也不会更改堆栈上已有的调用代码。您不能更改
main
的code对象以使其不调用foo
(尽管您可以更改foo
的code对象,这将在main
调用foo
时生效)。如果您对python中的字节码级内容感兴趣,请允许我介绍dis
,编译
和代码类型
不要在生产代码中执行这些操作
您可以将
python代码(作为字符串)编译成一个code对象,然后该对象可以重写functions\uuuuuuuuuuuuuuuuu
属性
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.
| ...
这就像编写汇编代码一样,可能会导致seg故障、python解释器崩溃或更糟。你知道什么时候唯一的文档是不是为胆小的人准备的。
开发人员并不打算直接使用它
如果您想查看实际执行的字节码,可以使用dis
。这是“拆解”的缩写
看看python代码实际上是如何执行的,这很有趣
我不确定你到底想用这个堆栈做什么,但我相当确定它到底是什么,python的开发人员已经确保这并不容易,因为这在python中是不应该涉及的。这些类型只存在于python中是出于内省的原因(比如通过检查函数的调用签名来查看函数在运行时的参数)如果您对python中的字节码级内容感兴趣,那么让我介绍一下
dis
、compile
和CodeType
不要在生产代码中执行这些操作
您可以将
python代码(作为字符串)编译成一个code对象,然后该对象可以重写functions\uuuuuuuuuuuuuuuuu
属性
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.
| ...
这就像编写汇编代码一样,可能会导致seg故障、python解释器崩溃或更糟。你知道什么时候唯一的文档是不是为胆小的人准备的。
开发人员并不打算直接使用它
如果您想查看实际执行的字节码,可以使用dis
。这是“拆解”的缩写
看看python代码实际上是如何执行的,这很有趣
我不确定你到底想用这个堆栈做什么,但我相当确定它到底是什么,python的开发人员已经确保这并不容易,因为这在python中是不应该涉及的。这些类型只存在于python中是出于内省的原因(比如通过检查函数的调用签名来查看函数在运行时的参数)这不会修改原始函数
foo
,但是,它通过重新指定全局名称foo
,将其替换为完全无关的函数。(这可能是OP想要的,也可能不是。)这是真的,虽然这确实有帮助,但我想知道是否有可能替换堆栈中的东西。例如,修改执行流中的当前行/位置,更改main的底层字节码等。@JonathanBurk:foo
在foo2
运行时不在堆栈上,所以我不确定您为什么要谈论堆栈。你的目标是摆弄