我的问题是这样的:我需要更改函数的行为方式,但无法访问或更改该函数所在的文件。不过,我可以import
,并且我想稍微改变一下实现。但是,由于我无法访问源代码本身,因此无法直接更改它。我实际上想更改函数实现,以便
import
的所有其他文件也将具有新函数。我目前正在尝试操作函数的
__code__.co_code
属性的代码字节(我知道这是非常糟糕的软件实践,但我真的别无选择。)。
__code__.co_code
返回一系列字节字符,这是非常难以理解并且极难更改的(我的意思是,我将如何使用字节编写代码??)。我想将一个新的代码对象注入到该函数中。有没有办法首先将包含新实现的Python字符串转换为一系列字节字符,然后将其安全地注入到旧函数中?对于一个最小的可重现示例,假设我有以下函数:
def func1():
return 1
我想将其更改为:
def func1():
return 0
我已经成功访问了函数的 __code__.co_code
属性的字节码序列,如下所示:
def func1():
return 1
code_obj = func1.__code__.co_code
print(code_obj) # prints b'd\x01S\x00'
new_code = b'd\x01S\x00' # copied the original code bytes sequence. How am I going to write `return 0` in bytes?
func1.__code__.co_code = new_code
print(func1)
code_obj2 = func1.__code__.co_code
它给了我这个错误:
Traceback (most recent call last):
File "C:\Program Files\JetBrains\PyCharm 2024.1\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode
coro = func()
File "<input>", line 7, in <module>
AttributeError: readonly attribute
它告诉我无法更改函数的 __code__.co_code
属性。此外,我真的不知道如何以字节序列编写新函数实现(
return 0
)。我知道我可能可以使用 AST,但我也不知道如何使用它们。谁能帮我?我真的被困在这里了。 (旁注:我不能只是用新的实现来隐藏旧函数,因为我希望导入库的其他文件也进行更改。另外,我不想使用
import lib; lib.old_function = new_function
在模块中设置函数.)
当心!我不是专家。我不知道这是否是一个坏主意,如果是坏主意,我不知道它会坏到什么程度。
#!/usr/bin/env python3
a=1
print(f"a={a}") # a=1
def func():
global a
a = a+1
print("func()") # func()
func()
print(f"a={a}") # a=2
source_code = """
global a
a = a+17
"""
code_obj = compile(source_code, '<string>', 'exec')
print("func.__code__ = code_obj")
func.__code__ = code_obj
print("func()") # func()
func()
print(f"a={a}") # a=19
显然,这个示例仅适用于没有参数且没有显式返回值的函数。请不要问我如何让它适用于带有参数或返回值的函数。