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

如何将已有函数的签名复用为包装器函数的*args、**kwargs及返回值的类型标注?

How to Properly Type Annotate *args and **kwargs for a Wrapper Function Matching the Original Function's Signature

Great question! When you need to wrap an existing function (that you can't modify) and want your wrapper to mirror its exact parameter types and return type, Python's modern typing tools have a clean solution for this—using ParamSpec and TypeVar. Let's break this down step by step.

First, let's ground this in your example scenario. Let's assume our pre-typed log function looks something like this (I'll add concrete types for clarity):

from typing import Any

def log(level: str, *messages: str, **extra: Any) -> None:
    """A pre-existing log function with full type annotations."""
    print(f"[{level}]", *messages, extra)

Now, to create a debug wrapper that perfectly inherits log's parameter and return types, here's the correct approach:

from typing import ParamSpec, TypeVar, Callable

# Define a parameter spec to capture the original function's full parameter signature
P = ParamSpec("P")
# Define a type variable to capture the original function's return type
R = TypeVar("R")

# Explicitly link the pre-defined log function to our ParamSpec and TypeVar
# This tells static type checkers that log follows the (P) -> R signature
log: Callable[P, R]

def debug(*args: P.args, **kwargs: P.kwargs) -> R:
    return log(level="debug", *args, **kwargs)

Why This Works

  • ParamSpec[P] acts as a dynamic placeholder that captures the full parameter structure of the log function—including positional arguments (*args) and keyword arguments (**kwargs).
  • TypeVar[R] captures the return type of log, ensuring our wrapper returns exactly the same type as the original function.
  • By annotating log as Callable[P, R], we create a direct link between the wrapper's signature and log's existing type annotations. Static checkers like mypy or pyright will recognize this connection and validate that debug adheres strictly to log's signature.

Key Notes

  1. This requires Python 3.10 or later (since ParamSpec was introduced in 3.10). If you're on an older version, you can use the typing_extensions module's backported ParamSpec.
  2. The original log function must have complete type annotations for this to work with static type checkers. If log was untyped, static tools wouldn't have enough information to validate the wrapper's signature (as you noted, inspect.signature is dynamic and won't help with static checks).

Testing the Type Checker

If we try to misuse debug in a way that violates log's signature, the type checker will catch it immediately. For example:

# This throws a type error (log expects `level` as a string, not an integer)
debug(level=123, "test message")
# This is valid, matching log's expected signature
debug("user logged in", user_id=123)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 09:37:29