当前位置: 首页 > 知识库问答 >
问题:

*args和**kwargs的类型批注

路雅懿
2023-03-14

我正在用抽象基类尝试Python的类型注释来编写一些接口。有没有办法注释*args**kwargs的可能类型?

例如,如何表示函数的合理参数是一个int或两个intstype(args)给出了Tuple,所以我猜应该将该类型注释为Union[Tuple[int,int],Tuple[int]],但这不起作用。

from typing import Union, Tuple

def foo(*args: Union[Tuple[int, int], Tuple[int]]):
    try:
        i, j = args
        return i + j
    except ValueError:
        assert len(args) == 1
        i = args[0]
        return i

# ok
print(foo((1,)))
print(foo((1, 2)))
# mypy does not like this
print(foo(1))
print(foo(1, 2))

来自mypy的错误消息

t.py: note: In function "foo":
t.py:6: error: Unsupported operand types for + ("tuple" and "Union[Tuple[int, int], Tuple[int]]")
t.py: note: At top level:
t.py:12: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:14: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 2 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"

mypy不喜欢函数调用这样是有道理的,因为它期望调用本身中有一个tuple。开箱后的添加也给出了一个我看不懂的打字错误。

如何注释*args**kwargs的合理类型?

共有3个答案

柳宪
2023-03-14

作为对前面答案的简短补充,如果您试图在Python 2文件上使用mypy,并且需要使用注释来添加类型而不是注释,则需要分别为argskwargs的类型加上***前缀:

def foo(param, *args, **kwargs):
    # type: (bool, *str, **int) -> None
    pass

这被mypy视为与下面相同,Python 3.5版本的foo

def foo(param: bool, *args: str, **kwargs: int) -> None:
    pass
暴奕
2023-03-14

正确的方法是使用@重载

from typing import overload

@overload
def foo(arg1: int, arg2: int) -> int:
    ...

@overload
def foo(arg: int) -> int:
    ...

def foo(*args):
    try:
        i, j = args
        return i + j
    except ValueError:
        assert len(args) == 1
        i = args[0]
        return i

print(foo(1))
print(foo(1, 2))

请注意,您没有向实际实现中添加@重载或类型注释,这些注释必须在最后。

您需要一个新版本的键入和mypy来获得对存根文件之外@重载的支持。

您还可以使用它来改变返回的结果,从而明确哪些参数类型对应于哪个返回类型。例如。:

from typing import Tuple, overload

@overload
def foo(arg1: int, arg2: int) -> Tuple[int, int]:
    ...

@overload
def foo(arg: int) -> int:
    ...

def foo(*args):
    try:
        i, j = args
        return j, i
    except ValueError:
        assert len(args) == 1
        i = args[0]
        return i

print(foo(1))
print(foo(1, 2))
江子石
2023-03-14

对于可变位置参数(*args)和可变关键字参数(**kw),您只需要指定一个此类参数的预期值。

从类型提示PEP的任意参数列表和默认参数值部分:

任意参数列表也可以进行类型注释,以便定义

def foo(*args: str, **kwds: int): ...

是可接受的,这意味着,例如,以下所有内容都表示具有有效参数类型的函数调用:

foo('a', 'b', 'c')
foo(x=1, y=2)
foo('', z=0)

因此,您应该像这样指定您的方法:

def foo(*args: int):

但是,如果你的函数只能接受一个或两个整数值,你不应该使用*args,使用一个显式的位置参数和第二个关键字参数:

def foo(first: int, second: Optional[int] = None):

现在,函数实际上被限制为一个或两个参数,如果指定,这两个参数都必须是整数*args始终表示0或更多,并且不能被类型提示限制为更具体的范围。

 类似资料:
  • 问题内容: 我正在尝试使用具有抽象基类的Python类型注释来编写一些接口。有没有一种方法来注释可能的类型和? 例如,如何表达一个函数的明智参数是一个或两个?给出,所以我的猜测是将类型注释为,但这是行不通的。 来自mypy的错误消息: Mypy不喜欢此函数调用是有道理的,因为它希望调用本身中包含a。解压后的附加内容还会产生我不理解的输入错误。 一个人如何诠释明智的类型和? 问题答案: 对于可变位置

  • 用*args和**kwargs只是为了方便并没有强制使用它们. 当你不确定你的函数里将要传递多少参数时你可以用*args.例如,它可以传递任意数量的参数: >>> def print_everything(*args): for count, thing in enumerate(args): ... print '{0}. {1}'.format(count, thing) ..

  • 问题内容: 在 Python的2.x的 (我用2.7),这是使用默认参数用正确的方式和? 我已经找到了与此主题相关的SO问题,但这是针对 Python 3的 : 使用 args,* kwargs和可选的/默认参数调用Python函数 在那里,他们说此方法有效: 在2.7中,结果为。有没有推荐的方法来定义这种功能? 我以这种方式工作,但我猜有更好的解决方案。 问题答案: 只需将默认参数放在: 现在,

  • 问题内容: Python-使用args和*kwargs[副本] 问题答案: 1650 语法为和。名称和仅是约定,但没有使用它们的硬性要求。 你会使用,当你确定不是多少个参数可能会被传递给你的函数,也就是说,它允许你传递的参数任意数量给你的函数。例如: 同样,允许你处理尚未预先定义的命名参数: 你也可以将它们与命名参数一起使用。显式参数首先获取值,然后将其他所有值传递给argsand *kwargs

  • 问题内容: 究竟什么和意味着什么? 根据Python文档,从表面上看,它传入了一个参数元组。 打印输出: 您如何有效地使用它们? 问题答案: 将和或作为函数定义的参数列表的最后一项放置,可使该函数接受任意数量的参数和/或关键字参数。 例如,如果你想编写一个返回所有参数总和的函数,则无论你提供多少,都可以这样编写: 当你覆盖某个函数并希望使用用户传入的任何参数调用原始函数时,它可能更常用于面向对象的

  •   *args 和 **kwargs 都允许将可变数量的参数传递给函数。当不确定要在函数中传递的参数数量时,将使用它们。   *args 允许你将可变数量的参数传递给函数。 def addNumbers(*numbers):     sum = 0     for number in numbers:         sum = sum + number     print("Sum: "