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

Mypy插件get_method_hook无法获取导入类型ClassDef的body内容

Mypy插件get_method_hook无法获取导入类型ClassDef的body内容

我完全理解你遇到的这个问题——在mypy插件的get_method_hook里处理导入的类时,类的defn.defs.body是空的,导致没法获取类内部的成员细节,这确实是mypy插件开发中很常见的一个坑,核心原因是mypy的增量式、模块化分析机制。

为什么会出现这个问题?

mypy为了提升分析性能,默认不会在加载当前模块时,全量导入外部模块的所有类定义细节。对于导入的类,它只会先加载符号表级别的信息(比如类的名称、对外暴露的类型签名),而不会立即解析类的完整定义体(body)。只有当这个类所在的模块被主动分析时,它的body才会被填充。所以当你在当前模块的get_method_hook里访问导入类的body时,它还没被加载,自然是空的。

解决方法:强制触发导入类的全量分析

我们可以通过mypy的API,主动触发导入类所在模块的分析,确保类的完整定义体被加载。具体来说,就是通过类的完整名称,让mypy去获取并分析对应的类型定义,这样就能拿到完整的body了。

修改你的alter_invoke_return_type函数如下:

def alter_invoke_return_type(ctx: MethodContext) -> Type:
    my_type = cast(Instance, ctx.type).type

    # 处理导入类的情况:若body为空,强制触发全量分析
    if not my_type.defn.defs.body:
        # 通过类的完整名称,获取已全量分析的Instance类型
        # 这一步会触发mypy加载并分析该类所在的模块
        analyzed_instance = ctx.api.named_type(my_type.fullname)
        # 更新为已全量分析的TypeInfo
        my_type = cast(Instance, analyzed_instance).type

    # 现在可以正常遍历成员和访问body了
    for member_name, member_type in my_type.names.items():
        print(f"Member property {member_name} has type {member_type}")

    # 此时body应该已被填充,断言不会触发
    assert len(my_type.defn.defs.body) != 0, f"Type {my_type.fullname} has no body"

    return ctx.default_return_type

关键细节说明

  1. ctx.api.named_type的作用:这个API会根据类的完整名称(比如my_pkg.foo.MyClass),返回对应的Instance类型。在这个过程中,mypy会自动检查该类所在的模块是否已被分析,如果没有,就会触发模块的全量分析,从而填充类的defn.defs.body。
  2. 性能注意事项:强制触发外部模块的全量分析会带来一定的性能开销,但对于需要获取类内部细节的插件功能来说,这是必要的代价。只要你的插件逻辑不是极端频繁地触发这个操作,性能影响是可控的。
  3. 关于AST访问的合理性:你通过访问ClassDef的body来提取成员信息的方式是完全正确的——这是获取类内部定义细节的标准方式,只要确保类的定义已经被全量分析,这个方法就可靠。

验证你的MWE

修改插件后,在bar.py中调用MyClass.invoke()时,插件就能成功获取MyClass的完整body,包括outer、outer2等成员的定义细节,不再是空的。

备注:内容来源于stack exchange,提问作者DEls

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 17:49:30