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

如何从Python包中提取指定脚本实际调用的函数?

不修改原包前提下提取脚本依赖的包内函数

完全可以做到,分识别依赖函数和提取为独立文件两步操作:

一、识别脚本调用的mypackage内函数

1. 静态分析(无需运行脚本)

用Python内置的ast模块解析脚本的抽象语法树,追踪所有来自mypackage的函数调用:

import ast
import importlib

def get_mypackage_deps(script_path):
    used_funcs = set()
    with open(script_path, 'r', encoding='utf-8') as f:
        tree = ast.parse(f.read())

    # 遍历所有调用节点
    for node in ast.walk(tree):
        # 处理形如`mypackage.mymodule.func1()`的调用
        if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
            try:
                # 解析模块对象
                mod_path = []
                current = node.func.value
                while isinstance(current, ast.Attribute):
                    mod_path.append(current.attr)
                    current = current.value
                if isinstance(current, ast.Name):
                    mod_path.append(current.id)
                    mod_path.reverse()
                    mod_fullname = '.'.join(mod_path)
                    if mod_fullname.startswith('mypackage'):
                        func_name = node.func.attr
                        used_funcs.add((mod_fullname, func_name))
            except:
                continue
        # 处理形如`from mypackage.mymodule import func1; func1()`的调用
        elif isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
            func_name = node.func.id
            # 检查全局变量中的函数是否来自mypackage
            if func_name in globals():
                func_obj = globals()[func_name]
                if hasattr(func_obj, '__module__') and func_obj.__module__.startswith('mypackage'):
                    used_funcs.add((func_obj.__module__, func_name))
    return used_funcs

2. 动态追踪(运行脚本,准确率更高)

用sys.settrace跟踪脚本运行时的所有函数调用,过滤出mypackage内的函数:

import sys
import importlib

traced_funcs = set()

def trace_handler(frame, event, arg):
    if event != 'call':
        return trace_handler
    # 获取当前调用函数的模块名
    mod_name = frame.f_globals.get('__name__', '')
    if mod_name.startswith('mypackage'):
        func_name = frame.f_code.co_name
        traced_funcs.add((mod_name, func_name))
    return trace_handler

# 启动追踪并运行脚本
sys.settrace(trace_handler)
importlib.import_module('your_script_name')  # 替换为你的脚本名(不含.py)
sys.settrace(None)

二、提取函数为独立文件

用inspect模块获取函数源代码,写入新文件,同时处理必要的依赖:

import inspect
import importlib

def extract_funcs(func_list, output_file):
    with open(output_file, 'w', encoding='utf-8') as f:
        # 先写入外部依赖的导入语句(比如numpy)
        f.write('import numpy as np\n\n')
        
        for mod_fullname, func_name in func_list:
            # 导入目标模块
            module = importlib.import_module(mod_fullname)
            func = getattr(module, func_name)
            # 获取函数源代码
            try:
                source_code = inspect.getsource(func)
                f.write(f'# 来自 {mod_fullname}\n{source_code}\n\n')
            except OSError:
                print(f"无法获取函数 {func_name} 的源代码")

# 使用前面识别出的函数列表
extract_funcs(traced_funcs, 'extracted_mypackage_funcs.py')

注意事项

  • 静态分析无法识别动态调用(比如getattr(mypackage.mymodule, 'func1')()),这种场景优先用动态追踪。
  • 如果提取的函数依赖mypackage内的其他函数、常量或类,需要递归识别并提取,否则独立文件会因缺失依赖报错。
  • 类方法的提取需要特殊处理,通常需要提取整个类而非单个方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 21:37:28