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

如何从Python代码对象截取代码片段执行以适配特殊导入场景?

问题:基于模块代码对象实现懒导入代码片段的截取与执行

这是此前关于「Python类定义或元类是否存在‘类定义完成后’的特殊方法?」问题的续篇。为处理循环引用,我实现了可保留类型提示的懒导入方案,代码如下:

import dataclasses
import inspect

lazy_chunks_key = '__lazy_chunks__'


@dataclasses.dataclass
class LazyChunk:
    _code: str
    _global: dict
    _local: dict

    def _load(self):
        if self._code:
            exec(self._code, self._global, self._local)
            self._code = ''

    def __getattr__(self, item):
        self._load()
        if item in self._local:
            return self._local[item]
        if item in self._global:
            return self._global[item]
        raise NameError(item)

    def __bool__(self):
        return False


def lazy_chunk():
    import re
    stack = inspect.stack()[1]
    with open(stack.filename, encoding='utf-8') as _src:
        src = iter(_src)
        for _ in range(stack.lineno): next(src)
        spacing, code = re.match(r"( *)([^ ].*)?", next(src)).groups()
        chunk_ind = len(spacing)
        code += '\n'
        while (line := next(src, None)) is not None:
            spacing, line_code = re.match(r"( *)([^ ].*)?", line).groups()
            if not line_code: continue
            if (_ind := len(spacing)) < chunk_ind: break
            code += ' ' * (_ind - chunk_ind) + line_code + '\n'
    frame = stack.frame
    frame.f_locals.setdefault(lazy_chunks_key, []).append(res := LazyChunk(code.strip(), frame.f_globals, frame.f_locals))
    return res

在结构体工厂中,我通过lazy chunk获取相关类型:

def set_fields_from_annotations(cls: typing.Type[_CStruct]) -> typing.Type[_CStruct]:
    if not (annotations := getattr(cls, '__annotations__', None)): return cls
    global_namespace = getattr(sys.modules.get(cls.__module__, None), '__dict__', {})
    global_namespace[cls.__name__] = cls
    local_namespace = dict(vars(cls))

    def str_eval_with_lazy(v):
        if isinstance(v, str):
            for chunk in global_namespace.pop(lazy_chunks_key, ()):
                chunk._load()
            return eval(v, global_namespace, local_namespace)
        return v

    ... # passing `str_eval_with_lazy` to fields and call it to get actual type when it is needed

lazy_chunk的使用示例如下:

# tree.py
from .node import Node


@set_fields_from_annotations
class Node(ctypes.Structure):
    first_node: Node


# node.py
if lazy_chunk():
    from .tree import Tree


@set_fields_from_annotations
class Node(ctypes.Structure):
    tree: 'Tree'
    value: ctypes.c_uint
    key: ctypes.c_uint
    parent: 'ctypes.POINTER(Node)'
    child: 'ctypes.POINTER(Node)'

但扩展使用场景时,从源码文件切割代码的方式不再可行,例如zipimport或导入预编译代码的场景。为解决该问题,请问是否有方法获取模块代码对象,截取代码片段并在eval中运行?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:25:53