Python 键入 returns None 的函数,如果列表 arg 仅包含 None

Python typing for function that returns None if list arg only contains None

我正在使用一个有点像这样的函数(超级简化,例如):

def foo(*stuff: None | int):
    stuff_not_none = [x for x in stuff if x is not None]
    if len(stuff_not_none) is 0:
        return None
    return sum(stuff_not_none)

如果我调用该函数使用:

我试过泛型/重载,但我无法弄清楚这个谜题。我怎样才能做到这一点?

解决方法:

from typing import overload

@overload
def foo(*stuff: None) -> None: ...  # type: ignore[misc]

@overload
def foo(*stuff: int | None) -> int: ...

def foo(*stuff: int | None) -> int | None:
    stuff_not_none = [x for x in stuff if x is not None]
    if len(stuff_not_none) is 0:
        return None
    return sum(stuff_not_none)
    
reveal_type(foo(None, None))  # revealed type is None
reveal_type(foo(1, 2, 3))  # revealed type is int
reveal_type(foo(None, 2, None, 4))  # revealed type is int
foo('a', 'b')  # error: no matching overload

Mypy 讨厌这种东西,因为重载重叠。但是你会发现,如果你在正确的地方添加一个 type: ignore 注释,无论如何它都完全能够推断出正确的类型。 (我是一个 typeshed 维护者,我们在 typeshed 一直 做这种事情。)

请注意,重载的顺序非常重要:类型检查器将始终首先尝试第一个重载,然后,只有当它不匹配时,他们才会尝试第二个重载。当我们传入 ints 和 Nones 的混合时,这就是我们如何获得 int 显示类型:第一个重载不匹配,因为存在 ints,所以类型检查器被迫尝试第二次重载。

Mypy 游乐场演示:https://mypy-play.net/?mypy=latest&python=3.10&gist=ff07808e0a314208fdfa6291dcf9f717