代码之家  ›  专栏  ›  技术社区  ›  Kracekumar

python mypy无法从联合返回类型推断类型

  •  2
  • Kracekumar  · 技术社区  · 7 年前

    这是示例代码

    from typing import Dict, Union, Tuple
    
    
    def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
        if data['start'] and data['end']:
            return data['start'], data['end']
        return 1, 1
    
    select_range({})
    

    MyPY输出:

    mypy different_return.py
    different_return.py:6: error: Incompatible return value type (got 
    "Tuple[Union[str, int], Union[str, int]]", expected "Tuple[int, int]")
    

    即使其中一个字典值是 int ,mypy无法推断。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Martijn Pieters    7 年前

    即使其中一个字典值是int,mypy也无法推断出这一点。

    Mypy是对的。您的代码有一个错误,mypy正确地标记了它。你的代码不能保证 data['start'] data['end'] 总是整数。

    你的 data 签名是 Dict[str, Union[str, int]] ,因此这些值具有 Union[str, int] 是的。我的 必须 假设进来总是正确的 {'start': '2018-07-12', 'end': -42} ,所以返回值 必须 Tuple[Union[str, int], Union[str, int]] 是的。你声称函数返回 Tuple[int, int] 与此冲突。

    什么都不重要 事实上 在运行时发生。这不是重点;mypy是一个静态类型检查器,旨在帮助您避免运行时行为错误。重要的是,根据类型提示,它是 可能的 传入的非整数值 start end ,因此typechecker无法保护您免受将来代码中错误的影响,这些错误会意外地为这两个键中的任何一个设置字符串值。

    如果你在字典中传递结构化数据,你总是要和mypy争这个,因为字典确实是错误的结构。你真的想使用命名元组或 a dataclass 在这里。

    我在用这个名字 FooBar 在这里,但对于您的特定应用程序,我相信您传递的数据结构会有一个更好的名称:

    from typing import NamedTuple
    
    class FooBar(NamedTuple):
        start: int
        end: int
        # other fields, perhaps with defaults and Optionals
    
    
    def select_range(data: FooBar) -> Tuple[int, int]:
        if data.start and data.end:
            return data.start, data.end
        return 1, 1
    
        2
  •  -1
  •   Konstantin Kozlenko    7 年前

    代码一切都很好。你忘了给你函数参数:

    from typing import Dict, Union, Tuple
    
    
    def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
        print (data)
        if data['start'] and data['end']:
            return data['start'], data['end']
        return 1, 1
    
    print (select_range({"start":[1,5], 'end':[2,6]}))
    

    使用此选项查找一些参数:

    from typing import Dict, Union, Tuple

    def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
    #    print (data)
        if 'start' in data and 'end' in data:
            return data['start'], data['end']
        return 1, 1
    
    print (select_range({"start":[5], 'end':[6]}))
    #select_range({})
    

    ([5],[6])是工作的结果

    推荐文章