【问题标题】:Python: How to write typing.overload decorator for bool arguments by valuePython:如何按值为 bool 参数编写 typing.overload 装饰器
【发布时间】:2021-11-23 00:05:04
【问题描述】:

我想问的示例代码如下。
互联网上的示例都没有尝试像这样重载参数值。
其中一个参数是 bool 值,我想重载一个基于 bool 值而不是通常的参数类型的方法。

from typing import overload, Union

@overload
def myfunc(arg:bool=True)-> str: ...

@overload
def myfunc(arg:bool=False)-> int: ...

def myfunc(arg:bool)->Union[int, str]:
    if arg: return "something"
    else: return 0

上述示例代码中的重载代码是否正确?
您能否提供一个提到这种重载的示例/博客/来源,因为我在 Python 文档和 pep-484

中找不到任何内容

我发现一种可能的方法是使用typing.Literal,就像latest python docs (since python v3.8)中使用的那样

from typing import overload, Union, Literal

@overload
def myfunc(arg:Literal[True])-> str: ...

@overload
def myfunc(arg:Literal[False])-> int: ...

def myfunc(arg:bool)->Union[int, str]:
    if arg: return "something"
    else: return 0

但是我还不能迁移到 python 3.8,因为我正在处理仍然在 python 3.6 上的生产代码,很快就会升级到 3.7。
因此,我仍在寻找有关如何在 python 3.6 中实现这一目标的答案

【问题讨论】:

    标签: python overloading mypy static-typing pyright


    【解决方案1】:

    安装typing-extensions 模块,该模块包含各种类型结构的官方反向移植。然后,做:

    from typing import overload, Union
    
    # typing_extensions defines Literal for Python 3.7 and earlier, but
    # re-exports it from 'typing' for later versions of Python.
    from typing_extensions import Literal
    
    @overload
    def myfunc(arg: Literal[True]) -> str: ...
    
    @overload
    def myfunc(arg: Literal[False]) -> int: ...
    
    @overload
    def myfunc(arg: bool) -> Union[str, int]: ...
    
    def myfunc(arg: bool) -> Union[int, str]:
        if arg: return "something"
        else: return 0
    

    请参阅mypy docs on literal types 中的第一个示例,了解为什么我在 bool 中包含第三个重载。

    【讨论】:

    • 谢谢!!! @erictraut 在我创建的相同 here 的 pyright 问题中回答了这个问题“你走在正确的轨道上。你需要使用 Literal[True] 和 Literal[False]。你可以通过导入 Literal 来解决对 Python 3.8 的需求输入扩展名并将注释放在引号中。这将阻止 python 解释器在运行时评估类型。"
    【解决方案2】:

    为默认(关键字)参数构建正确的accepted answer@overloading 可以如下实现:

    from typing import overload, Union, Literal
    
    @overload
    def myfunc(arg: Literal[True] = True) -> str: ...
    
    @overload
    def myfunc(arg: Literal[False]) -> int: ...
    
    def myfunc(arg: bool =  True) -> Union[int, str]:
        if arg: return "something"
        else: return 0
    

    第一个重载(Literal[True])用于对函数调用myfunc(True)myfunc()进行类型检查,而第二个重载(Literal[False])用于对函数调用myfunc(False)进行类型检查.

    【讨论】:

    • 这对接受的答案有何改进?
    • 这个例子展示了如何输入一个提供默认参数的函数,这在接受的答案中没有涵盖。特别是,上面的模式使像 mypy 这样的类型检查器能够在没有任何参数的情况下对 myfunc 的调用执行类型推断,例如x = myfunc().
    • 起初,我以为您不需要实际/非重载函数定义的类型注释。但实际上,您应该包含它们,否则您可能会在重载中得到类型错误并且它无法分辨 - 它会将所有 args 视为Any。这似乎没有按照应有的方式确定 - github.com/python/mypy/issues/8867#issuecomment-767842357
    • 另外:如另一个答案中所述,需要与实际函数定义相同的参数和注释的第三个重载。希望这将很快得到修复github.com/python/mypy/issues/6113
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 2014-09-20
    • 2012-10-28
    • 2015-02-21
    相关资源
    最近更新 更多