【问题标题】:Why does mypy infer the common base type instead of the union of all contained types?为什么 mypy 推断公共基类型而不是所有包含类型的并集?
【发布时间】:2019-12-18 12:42:13
【问题描述】:

当迭代异构序列时(例如,包含T1T2 类型的元素),mypy 推断目标变量的类型为object(或T1T2 之间共享的另一个基本类型, 例如float 如果元素是11.2):

xs = [1, "1"]
for x in xs:
    reveal_type(x)  # note: Revealed type is 'builtins.object*'

推断类型为Union[T1, T2] 不是更有意义吗?然后,如果T1T2 都具有公共基类所缺少的一些公共属性,则允许循环体访问该属性,而不会刺激强制转换或 isinstance 断言。

为什么 mypy 在这里推断单个共享基类型而不是 Union

【问题讨论】:

    标签: python python-3.x types type-inference mypy


    【解决方案1】:

    选择列表元素的公共基类(选择连接)而不是元素的联合是 mypy 做出的深思熟虑的设计选择。

    简而言之,问题在于,无论您选择两种解决方案中的哪一种,最终都会遇到对某人造成不便的极端情况。例如,在您想要修改添加到列表而不是仅仅读取它的情况下,推断联合将是不方便的:

    class Parent: pass
    class Child1(Parent): pass
    class Child2(Parent): pass
    class Child3(Parent): pass
    
    # If foo is inferred to be type List[Union[Child1, Child2]] instead of List[Parent]
    foo = [Child1(), Child2()]
    
    # ...then this will fail with a type error, which is annoying.
    foo.append(Child3())
    

    mypy 可能会尝试应用一些聪明的启发式方法来确定它是否应该推断出联接或联合,但这可能最终会导致最终用户相当混乱且难以预测。

    这也是一个在实践中很容易解决的问题——例如,您可以向变量添加显式注释:

    from typing import Union, Sized, List
    
    # If you want the union
    xs: List[Union[int, str]] = [1, "1"]
    
    # If you want any object with the `__len__` method
    ys: List[Sized] = [1, "1"]
    

    因此,鉴于这两个因素,实施一些奇特的启发式或完全切换到推断联合(并破坏大量现有代码)似乎并不值得。

    【讨论】:

    • 很好的答案,像往常一样。我一直认为这种行为类似于 Java 的泛型,例如无类型的ListList<Object> 的别名,令我惊讶的是mypy 选择了共同的祖先类——感谢您指出这一点。
    • @hoefling -- 你很接近 -- 类型 List 实际上是 List[Any] 的别名,其中 Any 是动态类型。 (mypy 文档有更多关于 Anyobject herehere 的信息)。但是,您实际上从未在示例中写过List 或任何其他类型提示——这种别名无关紧要。相反,类型检查器负责选择xs 应该具有的类型。而 mypy 通常偏向于推断具体的非动态类型。
    • 值得注意的是,这是一个特定于 mypy 的决定——PEP 484 实际上并没有强制要求任何特定的推理策略,因此类型检查器决定 xs 也同样有效改为输入List[Any]List[Union[int, str]]。例如,Facebook 的pyre 做出了相反的决定:他们倾向于推断联合而不是联接。这是 PEP 484/类型化 PEP 的一般模式——它们详细确定特定类型提示的含义,但将这些类型提示的实际推断/使用留给各个类型检查器。
    猜你喜欢
    • 1970-01-01
    • 2019-06-06
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多