Python中如何将字符串代码片段插入到原代码并编译运行?
有一种已经定义好格式的数据类型需要处理,但是多租户架构,每个客户的处理方式是不统一的。
比方说,要处理的都是数字,变量只有两个 x, y,但是甲客户是要处理 x + y,乙客户需要处理的是 x / y,这样来一个客户我就要写一个处理方法,然后重新发布我真的烦透了。我不想用规则引擎,因为我需要客户的处理逻辑和原来的代码一起合并然后线下 debug,这个是必须的。
所以有没有办法,能够把客户的代码插入到原来代码的办法,然后能打印出新的代码,还能把新的代码编译运行得到结果
谢谢各位
Python中如何将字符串代码片段插入到原代码并编译运行?
a = import(“模块名”)
a.xx
这种行不
或者用 eval
eval 不太安全
import ast
import sys
import types
def execute_code_snippet(original_code: str, snippet: str, insertion_point: str) -> dict:
"""
将代码片段插入到原始代码中并执行
Args:
original_code: 原始代码字符串
snippet: 要插入的代码片段
insertion_point: 插入位置标识(如函数名、类名后)
Returns:
执行结果的命名空间字典
"""
# 1. 解析原始代码为AST
original_ast = ast.parse(original_code)
# 2. 解析代码片段为AST
snippet_ast = ast.parse(snippet)
# 3. 查找插入位置
class InsertionVisitor(ast.NodeVisitor):
def __init__(self, insertion_point):
self.insertion_point = insertion_point
self.target_node = None
def visit_FunctionDef(self, node):
if node.name == self.insertion_point:
self.target_node = node
def visit_ClassDef(self, node):
if node.name == self.insertion_point:
self.target_node = node
visitor = InsertionVisitor(insertion_point)
visitor.visit(original_ast)
if not visitor.target_node:
raise ValueError(f"未找到插入点: {insertion_point}")
# 4. 插入代码片段
if isinstance(visitor.target_node, ast.FunctionDef):
# 插入到函数体开头
visitor.target_node.body = snippet_ast.body + visitor.target_node.body
elif isinstance(visitor.target_node, ast.ClassDef):
# 插入到类定义中
visitor.target_node.body = snippet_ast.body + visitor.target_node.body
# 5. 编译和执行
code_object = compile(original_ast, filename='<string>', mode='exec')
namespace = {}
exec(code_object, namespace)
return namespace
# 示例使用
original_code = """
def process_data(x):
result = x * 2
return result
class Calculator:
def add(self, a, b):
return a + b
"""
snippet = """
print(f"正在处理数据: {x}")
# 新增的预处理逻辑
if x < 0:
x = abs(x)
"""
# 在process_data函数开头插入代码片段
result_namespace = execute_code_snippet(original_code, snippet, "process_data")
# 测试执行
calc = result_namespace['Calculator']()
print(calc.add(2, 3)) # 输出: 5
result = result_namespace['process_data'](-5)
# 输出:
# 正在处理数据: -5
# 返回: 10
核心是使用AST解析和修改,比eval()或exec()直接拼接字符串更安全可控。
都是我们内部使用,我觉得 eval 还好,我在找有没有更好的
先写到文件,再执行文件
先写到文件,再动态 import ?
AST 现场修改代码
PyMacro 似乎就是这么干的
元编程? Ruby 是可以实现的,Python 不清楚。
不过 Python 不也是动态语言吗?有编译时?!还是只有运行时?
Py in Py
动态代码加载如果还觉得不够的话, 可能只能和楼上说的一样, 用元编程定义一个 DSL 了. 如果不想搞那么复杂, 搞一个中间文件格式出来, 所有客户的输入都统一转成这个格式, 然后再统一处理也行
exec
每当这种场景我就推荐用 golang 写基础逻辑,然后用 lua 写脚本来处理新的逻辑 hhh
动态 import, 你客户的处理代码加唯一标识,import 的时候按照你这个唯一标识的规则 import 进去执行。
lua 这种可以为每个函数单独设置 environment 的安全些。
采用框架-组件(插件)的架构,你的核心代码是框架,每个客户的代码是组件。不必重新发布,只更新组件就可以了。
猴子补丁
干脆自己写一个编译器 2333333333333333333333333333333333333333。
谢谢我去了解一下
刚好想知道 Python3.7 的 dataclass 是怎么实现初始化后统一调用__post_init__的,结果看源码发现是拼接 def __init__字符串,然后用 exec 动态生成方法的,和楼主的需求有点联系。
https://github.com/python/cpython/blob/master/Lib/dataclasses.py#L370
感谢
抽象方法?

