如何为一个接受可变数量参数的Python函数在存根文件中写类型注解?

1 投票
1 回答
74 浏览
提问于 2025-04-14 15:24

我想在一个存根文件里为以下函数写类型提示:

#foo.py
def foo(*args, bar="bar"): ...

我的要求如下:

  1. 如果没有给出 args,那么返回类型是 any
  2. 如果给出一个类型为 _Pargs,那么返回类型就是 _P
  3. 如果给出多个 args,它们必须都是同一种类型 _P,那么返回类型就是 tuple[_P, ...]

我尝试了以下方法:

# foo.pyi
@overload
def foo(bar: str = ...) -> Any: ...
@overload
def foo(args: _P, bar: str = ...) -> _P: ...
@overload
def foo(arg1: _P, *args: _P, bar: str = ...) -> tuple[_P, ...]: ...

但是运行 python -m mypy.stubtest foo 时出现了错误 stub argument "bar" is not keyword-only,而且通过在前面加上 *args 来让参数变成关键字参数,反而遮盖了下面的重载。

我还尝试了 foo(*, bar: str = ...),但这似乎并没有把 bar 标记为关键字参数。添加 * 后,错误信息从

error: foo.foo is inconsistent, stub argument "bar" is not keyword-only
Stub: in file /home/niklas/Desktop/test/foo.pyi:5
Overload(def (bar: builtins.str =) -> Any, def [_P] (args: _P`-1, bar: builtins.str =) -> _P`-1, def [_P] (arg1: _P`-1, *args: _P`-1, bar: builtins.str =) -> builtins.tuple[_P`-1, ...])
Inferred signature: def (arg1: _P`-1 = ..., bar: builtins.str = ..., *args)
Runtime: in file /home/niklas/Desktop/test/foo.py:1
def (*args, bar='bar')

变成了(注意第三行的星号 *):

error: foo.foo is inconsistent, stub argument "bar" is not keyword-only
Stub: in file /home/niklas/Desktop/test/foo.pyi:5
Overload(def (*, bar: builtins.str =) -> Any, def [_P] (args: _P`-1, bar: builtins.str =) -> _P`-1, def [_P] (arg1: _P`-1, *args: _P`-1, bar: builtins.str =) -> builtins.tuple[_P`-1, ...])
Inferred signature: def (arg1: _P`-1 = ..., bar: builtins.str = ..., *args)
Runtime: in file /home/niklas/Desktop/test/foo.py:1
def (*args, bar='bar')

1 个回答

0

在评论中,@undefined 和 @chepner 提供了解决方案。请注意第一个和第二个签名中的星号 *

# foo.pyi
@overload
def foo(*, bar: str = ...) -> Any: ...
@overload
def foo(args: _P, *, bar: str = ...) -> _P: ...
@overload
def foo(arg1: _P, *args: _P, bar: str = ...) -> tuple[_P, ...]: ...

撰写回答