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

如何实现兼容mypy --strict的函数包装且保留类型(无需重定义)?

问题场景

假设定义了这样一个带类型注解的函数:

def foo(arg: int, arg2: str, arg3: int) -> MyReturnType:
    # 函数实现

用functools.partial固定参数时,mypy能正确识别生成的safefoo的类型:

safefoo = functools.partial(foo, arg2="whatever")

但自己写包装函数(不管用不用@wraps),mypy都会报错Call to untyped function "safefoo" in typed context,比如这两种写法:

  • 直接写包装函数:
def safefoo(*args, **kwargs):
    # 这里要加额外逻辑
    return foo(*args, arg2="whatever", **kwargs)
  • 用functools.wraps装饰:
from functools import wraps

@wraps(foo)
def safefoo(*args, **kwargs):
    return foo(*args, arg2="whatever", **kwargs)

现在需要在不重新手动定义类型注解的前提下,让mypy认可这类自定义包装函数的类型。

解决办法

1. 用ParamSpec和TypeVar继承原函数类型(Python 3.10+)

利用标准库的类型工具,精准复用原函数的参数和返回类型定义,无需手动重复写:

from functools import wraps
from typing import TypeVar, ParamSpec, Callable

# 定义参数规范和返回值类型变量
P = ParamSpec("P")
R = TypeVar("R")

def wrap_fixed_arg(func: Callable[P, R], fixed_arg2: str) -> Callable[P, R]:
    @wraps(func)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
        # 在这里添加你的额外逻辑
        return func(*args, arg2=fixed_arg2, **kwargs)
    return wrapper

# 生成包装后的函数
safefoo = wrap_fixed_arg(foo, "whatever")

这种写法能让mypy完全推导safefoo的类型,和原函数foo的差异仅在于已固定的arg2参数。

2. 用typing.cast做类型转换

如果只是要快速通过mypy检查,可直接把包装函数强制转换为原函数对应的Callable类型:

from functools import wraps
from typing import Callable, cast

@wraps(foo)
def safefoo(*args, **kwargs):
    # 你的额外逻辑
    return foo(*args, arg2="whatever", **kwargs)

# 把safefoo转换为符合要求的类型:接受int和int参数,返回MyReturnType
safefoo = cast(Callable[[int, int], MyReturnType], safefoo)

注意:这种方式需要你清楚原函数的类型结构,若原函数类型后续变更,这里的转换语句也得同步调整。

3. 结合partial与包装逻辑

如果额外逻辑可以和参数固定操作拆分,也可以先通过partial固定参数,再在外层包装添加逻辑:

from functools import partial

def safefoo(*args, **kwargs):
    # 先执行你的额外逻辑
    # 用partial固定arg2参数
    prefixed_foo = partial(foo, arg2="whatever")
    return prefixed_foo(*args, **kwargs)

这种写法借助partial自带的类型推导能力,让mypy间接认可safefoo的类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 09:03:19