You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建支持便捷惰性注入的Python模块?

实现惰性注入的Python模块代理

要实现你需要的效果,核心是让模块中的变量(比如y)能动态反映依赖变量(比如x)的最新值,而不是模块导入时的静态快照。我们可以通过创建模块代理类,结合AST解析来延迟计算变量值,具体实现如下:

实现思路

  1. 编写lazy_import函数,返回一个模块代理对象,而非直接导入原模块。
  2. 解析目标模块的AST语法树,提取所有顶级变量的赋值表达式,记录变量与表达式的映射关系。
  3. 代理对象拦截属性的获取与设置:
    • 设置属性时,将值存储在自定义属性字典中。
    • 获取属性时,若该属性有对应的表达式,则基于当前的属性值重新计算表达式结果;若有自定义设置的值,则直接返回。

完整代码实现

injector_impl.py(lazy_import的实现)

import ast
import sys
import importlib.util

class LazyModule:
    def __init__(self, module_name):
        self.module_name = module_name
        self._custom_attrs = {}
        self._attr_exprs = self._parse_module_exprs(module_name)

    def _parse_module_exprs(self, module_name):
        # 定位模块文件并解析AST
        spec = sys.modules.get(module_name) or importlib.util.find_spec(module_name)
        if not spec or not spec.origin:
            raise ImportError(f"无法找到模块 {module_name}")
        
        with open(spec.origin, 'r', encoding='utf-8') as f:
            tree = ast.parse(f.read())
        
        attr_exprs = {}
        for node in ast.walk(tree):
            # 提取顶级单个变量的赋值表达式
            if isinstance(node, ast.Assign) and len(node.targets) == 1:
                target = node.targets[0]
                if isinstance(target, ast.Name):
                    var_name = target.id
                    expr_str = ast.unparse(node.value)
                    attr_exprs[var_name] = expr_str
        return attr_exprs

    def __getattr__(self, name):
        # 优先返回自定义设置的属性
        if name in self._custom_attrs:
            return self._custom_attrs[name]
        # 计算表达式对应的当前值
        if name in self._attr_exprs:
            return eval(self._attr_exprs[name], {}, self)
        # fallback到真实模块的属性(如函数、类)
        if self.module_name in sys.modules:
            return getattr(sys.modules[self.module_name], name)
        raise AttributeError(f"模块 {self.module_name} 不存在属性 '{name}'")

    def __setattr__(self, name, value):
        # 内部属性直接设置,外部属性存入自定义字典
        if name.startswith('_'):
            super().__setattr__(name, value)
        else:
            self._custom_attrs[name] = value

def lazy_import(module_name):
    return LazyModule(module_name)

测试代码

my_module.py

x = 4
y = x

injector.py

from injector_impl import lazy_import

m = lazy_import("my_module")
m.x = 5
print(m.y)  # 输出5

注意事项

  • 安全性:该实现使用了eval解析表达式,若目标模块包含恶意代码会存在风险,仅建议在可信代码场景下使用。
  • 复杂场景支持:当前实现仅处理顶级单个变量的赋值,若模块中有复杂表达式(如y = x * 2 + z)、条件赋值或嵌套结构,需要扩展AST解析逻辑。
  • 模块其他成员:对于模块中的函数、类等非变量成员,代理会自动从真实模块中获取,确保原有功能不受影响。

内容的提问来源于stack exchange,提问作者James Pinkerton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:05:31