如何使用多个可选的ARG键入超载功能?

发布于 2025-01-29 20:20:41 字数 885 浏览 1 评论 0 原文

我的功能具有多个带有默认值的Kwargs。其中之一(在中间的某个地方)是一个布线切换,可以控制返回类型。

我想用字面[true/fals] 为此方法创建两个过载,但要保持默认值。

我的想法是以下内容:

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 值,因为它先于agr a 带有默认值。

我如何正确地重载,以使

  • x() int
  • x(t = true) int int
  • 代码> x(t = false)→ str

I have a function with multiple kwargs with defaults. One of them (in the middle somewhere) is a boolean toggle that controls the return type.

I would like to create two overloads for this method with Literal[True/False] but keeping the default value.

My idea was the following:

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"

But mypy raises:

error: Overloaded function signatures 1 and 2 overlap with incompatible return types

I assume that is because x() will conflict.

But I cannot remove the default = False value in the second overload since it is preceded by arg a with a default.

How can I overload this properly such that

  • x()int
  • x(t=True)int
  • x(t=False)str

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

要走干脆点 2025-02-05 20:20:41

这是一个古老的问题。原因是您在两个分支中指定默认值,因此 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 作为夸尔格(#2)或arg(#3)。您也可以留下 默认值,然后 t 始终是Kwarg(再次#2)。这是防止在Kwarg之后放置ARG的需要的,这是 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)

您可以使用超载在这里

eLLIPSIS( ... )在过载签名中默认值表示“有默认值,请参阅实现其值”。它与类型检查器的实际值没有什么不同,但是使您的代码saner(默认值仅在实际签名中定义,而不是重复)。

It is an old problem. The reason is that you specify default value in both branches, so x() is possible in both and return type is undefined.

I have the following pattern for such cases:

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"

Why and how? You have to think about ways to call your function. First, you can provide a, then t can be given as kwarg (#2) or arg (#3). You can also leave a default, then t is always a kwarg (#2 again). This is needed to prevent putting arg after kwarg, which is SyntaxError. Overloading on more than one parameter is more difficult, but possible this way too:

@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)

You can play with overloading here.

Ellipsis (...) in overloaded signatures default values means "Has a default, see implementation for its value". It is no different from the actual value for the type checker, but makes your code saner (default values are defined only in actual signatures and not repeated).

我一直都在从未离去 2025-02-05 20:20:41

超载具有默认值是没有意义的,并且您 can 删除字面参数的默认值,只要您还从其他参数中删除默认值即可。

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

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

It makes no sense for overloads to have default values, and you can remove the defaults from the literal argument as long as you also remove the defaults from the other arguments.

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

@overload
def x(a: int | None, t: Literal[False], b: int | None ) -> str: ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文