我试图获取一个函数的源代码,向其添加代码,然后将其放回原始函数中。在
基本上是这样的:
new_code = change_code(original_code)
throwaway_module = ModuleType('m')
exec(new_code, throwaway_module.__dict__)
func.__code__ = getattr(throwaway_module, func.__name__).__code__
当new_code
不包含任何不在原始函数中的名称时,这种方法非常有效。在
但是,当new_code
包含一个变量名,而这个变量名在原始的func
中没有,那么在最后一行我得到了以下错误:
有什么想法吗?在
编辑:
我似乎找到了在CPython源代码中引发这个异常的地方(文件funcobject.c)。为了清楚起见,省略了一些行:
^{3}$这对你有帮助吗?:)
此异常是由于试图将代码对象分配给一个函数,该函数的关闭变量数与它来自的函数不同。如果那句话听起来像胡言乱语,那么你应该看看this answer。在
避免此问题的最简单方法是简单地以明显的方式重新分配现有名称,即}。通过这样做,代码对象总是与其匹配的闭包保持一致(稍后将详细介绍)。在您的例子中,这看起来像
f = g
而不是{func = getattr(throwaway_module, func.__name__)
。有没有什么原因你不能这样做,而是在处理内部实现细节?在为了更好地说明这里发生了什么,假设我们有一些愚蠢的函数。在
即使
^{pr2}$do_stuff
与dog
具有不同数量的局部变量,我们仍然可以成功地在它们之间重新分配代码对象。在但是,我们不能在}。在
cats
和dog
之间重新赋值,因为cats
关闭了参数{ValueError: dog() requires a code object with 0 free vars, not 1
只需将名称重新指定给所需的函数对象即可避免此问题。在
事实上,如果成功地为带有闭包的函数重新分配了代码对象,那么如果函数被执行,事情很可能不会如预期的那样进行。这是因为closed over变量与编译的代码分开保存,因此它们不匹配。在
事实证明,我们不能轻易地替换
__closure__
属性,因为它是只读的。如果你真的下定决心的话,你大概可以work around it,但这几乎肯定是个糟糕的主意。在有关函数对象属性的详细信息,请参见this answer和the docs。在
相关问题 更多 >
编程相关推荐