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

如何在不使用inspect的情况下静态构造Python函数Signature对象?

静态生成Python函数Signature对象的方案

不需要导入目标代码的话,用Python标准库的ast模块做静态语法分析是最简便可行的方案,以下是具体实现思路和代码:

核心思路

  1. 读取目标Python文件的文本内容,用ast.parse()解析成抽象语法树(AST)
  2. 遍历AST找到所有函数/方法定义节点(FunctionDef 或 AsyncFunctionDef)
  3. 从节点中提取参数名、类型注解、默认值、返回值注解等信息
  4. 用inspect.Signature和inspect.Parameter构造对应的Signature对象

代码实现

import ast
import inspect
from typing import Optional, List


def build_signature(func_node: ast.FunctionDef) -> inspect.Signature:
    params = []
    # 处理普通参数(含self/cls)
    for i, arg in enumerate(func_node.args.args):
        # 提取参数名
        param_name = arg.arg
        # 提取类型注解
        annotation = inspect.Parameter.empty
        if arg.annotation is not None:
            try:
                annotation = ast.unparse(arg.annotation)
            except AttributeError:
                # Python 3.8及以下可替换为astor.to_source(arg.annotation)
                annotation = ast.dump(arg.annotation, compact=True)
        
        # 提取默认值
        default = inspect.Parameter.empty
        if i >= len(func_node.args.args) - len(func_node.args.defaults):
            default_node = func_node.args.defaults[i - (len(func_node.args.args) - len(func_node.args.defaults))]
            try:
                default = ast.literal_eval(default_node)
            except (ValueError, SyntaxError):
                # 无法静态求值的默认值,用字符串形式保留
                default = ast.unparse(default_node)
        
        # 构造参数对象
        params.append(inspect.Parameter(
            name=param_name,
            kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
            default=default,
            annotation=annotation
        ))
    
    # 处理*args可变参数
    if func_node.args.vararg:
        vararg_name = func_node.args.vararg.arg
        vararg_annotation = inspect.Parameter.empty
        if func_node.args.vararg.annotation is not None:
            vararg_annotation = ast.unparse(func_node.args.vararg.annotation)
        params.append(inspect.Parameter(
            name=vararg_name,
            kind=inspect.Parameter.VAR_POSITIONAL,
            annotation=vararg_annotation
        ))
    
    # 处理**kwargs可变参数
    if func_node.args.kwarg:
        kwarg_name = func_node.args.kwarg.arg
        kwarg_annotation = inspect.Parameter.empty
        if func_node.args.kwarg.annotation is not None:
            kwarg_annotation = ast.unparse(func_node.args.kwarg.annotation)
        params.append(inspect.Parameter(
            name=kwarg_name,
            kind=inspect.Parameter.VAR_KEYWORD,
            annotation=kwarg_annotation
        ))
    
    # 处理返回值注解
    return_annotation = inspect.Parameter.empty
    if func_node.returns is not None:
        try:
            return_annotation = ast.unparse(func_node.returns)
        except AttributeError:
            return_annotation = ast.dump(func_node.returns, compact=True)
    
    return inspect.Signature(parameters=params, return_annotation=return_annotation)


# 示例用法
if __name__ == "__main__":
    # 用示例代码字符串代替读取文件内容
    code = """
def method_with_args(self, param_a: str, param_b: int = 123) -> str:
        \"\"\"
        Method with arguments and a return value.

        Args:
            param_a (str): A string parameter.
            param_b (int): An integer parameter.

        Returns:
            str: Concatenation of param1 and string representation of param2.
        \"\"\"
        return param_a + str(param_b)
    """
    tree = ast.parse(code)
    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef):
            sig = build_signature(node)
            print(sig)

注意事项

  • 对于无法静态求值的默认值(比如param = some_function()),ast.literal_eval会失败,此时代码会用ast.unparse将默认值的AST节点转换成字符串表示,保证Signature结构完整
  • Python 3.9及以上支持ast.unparse(),3.8及以下版本可安装astor库,用astor.to_source()替代
  • 如果需要处理复杂语法(比如泛型注解、类型变量),可以考虑第三方静态分析库libcst,它对Python语法的处理更鲁棒

第三方库可选方案(libcst)

import libcst
import inspect

def build_signature_with_libcst(code: str) -> inspect.Signature:
    module = libcst.parse_module(code)
    params = []
    return_annotation = inspect.Parameter.empty
    
    for node in module.body:
        if isinstance(node, libcst.FunctionDef):
            # 处理普通参数
            for param in node.params.params:
                param_name = param.name.value
                # 提取类型注解
                annotation = inspect.Parameter.empty
                if param.annotation:
                    annotation = libcst.Module([param.annotation.code]).code
                # 提取默认值
                default = inspect.Parameter.empty
                if param.default:
                    default = libcst.Module([param.default.code]).code
                params.append(inspect.Parameter(
                    name=param_name,
                    kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
                    default=default,
                    annotation=annotation
                ))
            # 处理返回值注解
            if node.returns:
                return_annotation = libcst.Module([node.returns.code]).code
            return inspect.Signature(parameters=params, return_annotation=return_annotation)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:05:34