如何使用多个可选参数来类型重载函数?

问题描述 投票:0回答:1

我有一个带有多个默认值的 kwargs 的函数。其中之一(在中间的某个地方)是控制返回类型的布尔切换。

我想使用

Literal[True/False]
为此方法创建两个重载,但保留默认值。

我的想法如下:

from typing import overload, Literal

@overload
def x(a: int = 5, t: Literal[True] = True, b: int = 5) -> int: ...

@overload
def x(a: int = 5, t: Literal[False] = False, b: int = 5) -> str: ...

def x(a: int = 5, t: bool = True, b: int = 5) -> int | str:
    if t:
        return 5
    return "asd"

但是 mypy 加注:

错误:重载函数签名 1 和 2 与不兼容的返回类型重叠

我认为这是因为

x()
会发生冲突。

但是我无法删除第二个重载中的默认

= False
值,因为它前面是带有默认值的 arg
a

我怎样才能正确地重载它,这样

  • x()
    int
  • x(t=True)
    int
  • x(t=False)
    str
python mypy python-typing
1个回答
9
投票

这是一个老问题。原因是您在两个分支中都指定了默认值,因此

x()
在两个分支中都是可能的,并且返回类型未定义。

对于这种情况,我有以下模式:

from typing import overload, Literal

@overload
def x(a: int = ..., t: Literal[True] = True, b: int = ...) -> int: ...

@overload
def x(a: int = ..., *, t: Literal[False], b: int = ...) -> str: ...

@overload
def x(a: int, t: Literal[False], b: int = ...) -> str: ...

def x(a: int = 5, t: bool = True, b: int = 1) -> int | str:
    if t:
        return 5
    return "asd"

为什么以及如何?您必须考虑调用函数的方法。首先,您可以提供

a
,然后
t
可以作为 kwarg (#2) 或 arg (#3) 给出。您也可以保留
a
默认值,然后
t
始终是 kwarg(再次#2)。这是为了防止将 arg 放在 kwarg 之后,即
SyntaxError
。重载多个参数比较困难,但也可以通过这种方式:

@overload
def f(a: int = ..., b: Literal[True] = ..., c: Literal[True] = ...) -> int: ...

@overload
def f(a: int = ..., *, b: Literal[False], c: Literal[True] = ...) -> Literal['True']: ...

@overload
def f(a: int = ..., *, b: Literal[False], c: Literal[False]) -> Literal['False']: ...

@overload
def f(a: int, b: Literal[False], c: Literal[True] = ...) -> Literal['True']: ...

@overload
def f(a: int, b: Literal[False], c: Literal[False]) -> Literal['False']: ...

def f(a: int = 1, b: bool = True, c: bool = True) -> int | Literal['True', 'False']:
    return a if b else ('True' if c else 'False')  # mypy doesn't like str(c)

您可以在这里玩重载。

重载签名默认值中的省略号 (

...

) 表示“有默认值,请参阅其值的实现”。它与类型检查器的实际值没有什么不同,但使您的代码更加清晰(默认值仅在实际签名中定义,不会重复)。

© www.soinside.com 2019 - 2024. All rights reserved.