为什么MyPy推断出常见的基本类型,而不是所有包含类型的联合? 您所在的位置:网站首页 infers翻译 为什么MyPy推断出常见的基本类型,而不是所有包含类型的联合?

为什么MyPy推断出常见的基本类型,而不是所有包含类型的联合?

2023-04-19 03:23| 来源: 网络整理| 查看: 265

百度翻译此文   有道翻译此文 问题描述

When iterating over a heterogeneous sequence (containing elements of type T1 and T2, say), mypy infers the target variable to have type object (or another base type shared between T1 and T2, e.g. float if the elements were 1 and 1.2):

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

Wouldn't it make more sense for the inferred type to be Union[T1, T2]? Then if both T1 and T2 have some common attribute which the common base class lacks, the loop body would be allowed to access that attribute without irritating casts or isinstance assertions.

Why does mypy infer a single shared base type instead of a Union here?

推荐答案

Picking the common base class of the list elements (picking the join) instead of taking the union of the elements is a deliberate design choice that mypy made.

In short, the problem is that no matter which of the two solutions you pick, you'll always end up with edge cases that end up being inconvenient for somebody. For example, inferring the union would be inconvenient in cases like the following where you want to modify or add to the list, instead of only reading it:

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

It's possible that mypy could perhaps try applying some clever heuristic to determine whether it should infer a join or a union, but that'll probably end up being fairly confusing and difficult to predict for end-users.

This is also a pretty easy issue to work around in practice -- for example, you could just add an explicit annotation to your variable:

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"]

So given these two factors, implementing some fancy heuristic or switching to inferring unions entirely (and disrupting a lot of existing code) doesn't really seem worth it.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有