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

如何在不丢失类型信息的情况下包装Python函数?

问题描述

我想给调用外部库的Python函数添加一些高级逻辑,比如:

class Example():
    def my_func(self, *args, **kwargs):
        return library.func(*args, **kwargs)

根据外部库的执行结果,可能需要执行不同操作,比如增加重试逻辑:

import time

class Example():
    def my_func(self, *args, **kwargs):
        try:
            return library.func(*args, **kwargs)
        except LibraryRateLimitError:
            # 简化的退避重试逻辑
            time.sleep(2)
            return self.my_func(*args, **kwargs)

但问题是,这个新函数丢失了所有类型信息。由于library.func结构复杂,有数十个参数,我不想手动标注类型。有没有办法静态告知类型分析器,这个包装后的函数和底层函数接收完全相同的参数?

解决方案

方法1:使用functools.wraps

functools.wraps会复制原函数的元数据(包括类型提示)到包装函数,主流类型检查器(如mypy、Pyright)和IDE都能识别这种方式:

import functools
import time
import library

class Example():
    @functools.wraps(library.func)
    def my_func(self, *args, **kwargs):
        try:
            return library.func(*args, **kwargs)
        except library.LibraryRateLimitError:
            time.sleep(2)
            return self.my_func(*args, **kwargs)

注意:如果原函数是实例方法,而包装函数属于另一个类,可能需要额外适配,但针对普通函数或同层级类方法,该方法足够实用。

方法2:使用typing.ParamSpec和ReturnType(Python 3.10+)

要实现更精准的类型传递,可以用ParamSpec定义原函数的参数规范,ReturnType提取原函数的返回类型,让类型检查器完全复用原函数的类型信息:

import time
import library
from typing import ParamSpec, ReturnType

P = ParamSpec('P')

class Example():
    def my_func(self, *args: P.args, **kwargs: P.kwargs) -> ReturnType[library.func]:
        try:
            return library.func(*args, **kwargs)
        except library.LibraryRateLimitError:
            time.sleep(2)
            return self.my_func(*args, **kwargs)

这种方式灵活性更高,即便你需要对参数做微调,也能保留大部分类型约束。

方法3:手动设置__signature__

如果前两种方法无法满足类型检查器或IDE的识别需求,可以用inspect.signature获取原函数的签名,直接赋值给包装函数的__signature__属性:

import inspect
import time
import library

class Example():
    def my_func(self, *args, **kwargs):
        try:
            return library.func(*args, **kwargs)
        except library.LibraryRateLimitError:
            time.sleep(2)
            return self.my_func(*args, **kwargs)

# 复制原函数的签名信息
Example.my_func.__signature__ = inspect.signature(library.func)

该方法能让IDE(如PyCharm)正确提示参数,类型检查器通常也能兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:35:24