Почему TypedDict не совместим с сопоставлением Mapping? - PullRequest
3 голосов
/ 19 февраля 2020

Рассмотрим следующий код:

from typing import Any, Mapping, TypedDict


class MyDict(TypedDict):
    foo: bool


def my_func_any(a: Mapping[str, Any]) -> None:
    print(a)


def my_func_bool(a: Mapping[str, bool]) -> None:
    print(a)


d: MyDict = {
    'foo': True
}

my_func_any(d)
my_func_bool(d)  # line 21

При проверке с помощью mypy==0.761:

test.py: 21: ошибка: аргумент 1 в "выдает следующую ошибку my_func_bool "имеет несовместимый тип" MyDict "; ожидал "Mapping [str, bool]"

Я ожидал, что и my_func_any(d), и my_func_bool(d) будут в порядке, но последнее является ошибкой. Это ошибка или я что-то упустил?

1 Ответ

4 голосов
/ 20 февраля 2020

Цитирование PEP 589 :

Согласованность типов

Во-первых, любой тип TypedDict соответствует Mapping[str, object].

[...]

  • A TypedDict со всеми значениями int не согласуется с Mapping[str, int], так как могут быть дополнительные не-int значения, не видимые через тип , из-за структурного подтипа. К ним можно получить доступ, например, с помощью методов values() и items() в Mapping. Пример:

    class A(TypedDict):
        x: int
    
    class B(TypedDict):
        x: int
        y: str
    
    def sum_values(m: Mapping[str, int]) -> int:
        n = 0
        for v in m.values():
            n += v  # Runtime error
        return n
    
    def f(a: A) -> None:
        sum_values(a)  # Error: 'A' incompatible with Mapping[str, int]
    
    b: B = {'x': 0, 'y': 'foo'}
    f(b)
    
...