Python mypy не может определить тип из возвращаемых типов объединения

Вот пример кода

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 не может этого сделать.


person Kracekumar    schedule 12.07.2018    source источник
comment
mypy правильно. У вас есть значения dict как Union[str, int], но тип возвращаемого значения в подписи как int. Измените тип возвращаемого значения или не указывайте тип значений в data.   -  person Jared Smith    schedule 12.07.2018
comment
Ваша функция принимает словарь, значения которого могут быть строками или целыми числами, и возвращает два таких значения. В таком случае вы не можете утверждать, что всегда возвращаете целые числа.   -  person Martijn Pieters    schedule 12.07.2018
comment
Я думаю, что у вас есть неправильное представление о том, что эти типы являются статическими, но вы думаете о фактических конкретных значениях, которые возвращаете во время выполнения. Системы статического типа работают не так.   -  person Jared Smith    schedule 12.07.2018


Ответы (2)


Несмотря на то, что одним из значений словаря является int, mypy не может этого сделать.

Mypy это правильно. В вашем коде есть ошибка, и mypy правильно ее помечает. В вашем коде нет гарантии, что data['start'] и data['end'] всегда будут целыми числами.

Ваша подпись data Dict[str, Union[str, int]], поэтому значения имеют тип Union[str, int]. Mypy должен предполагать, что всегда правильно передать {'start': '2018-07-12', 'end': -42}, поэтому возвращаемое значение должно быть Tuple[Union[str, int], Union[str, int]]. Ваше утверждение о том, что функция возвращает Tuple[int, int], противоречит this.

Неважно, что на самом деле происходит во время выполнения. Не в этом дело; mypy - это статическая проверка типов, предназначенная для защиты от ошибок в вашем поведении во время выполнения. Здесь важно то, что в соответствии с подсказками типа возможно передать нецелочисленные значения для start и end, поэтому проверка типов не может защитить вас от будущих ошибок в вашем коде, которые случайно установить строковое значение для любого из этих двух ключей.

Если вы передаете структурированные данные в словарях, вам всегда придется бороться с mypy по этому поводу, поскольку словари действительно являются неправильной структурой для этого. Вы действительно хотите использовать именованный кортеж или класс данных здесь.

Я использую здесь имя 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
person Martijn Pieters    schedule 12.07.2018

с кодом все хорошо. вы забываете получить параметры функции:

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]) - результат работы

person Konstantin Kozlenko    schedule 12.07.2018
comment
Нет, даже добавление значения также вызывает ту же ошибку. - person Kracekumar; 12.07.2018
comment
Нет, та же ошибка все равно будет возникать, потому что mypy - это средство проверки статического типа. Неважно, что на самом деле происходит во время выполнения. Кроме того, теперь вы передаете списки в качестве значений. Union[str, int] не означает, что значения являются списками целых чисел, значения должны быть либо целыми числами, либо строками. - person Martijn Pieters; 12.07.2018
comment
Я думаю, вы неправильно поняли, о чем идет речь. Вы понимаете, как работает подсказка типов, что означает синтаксис Dict[...], Union[...] и Tuple[...]? - person Martijn Pieters; 12.07.2018
comment
Я думаю, что проблема в том, что вы утверждаете в коде, который у вас есть в ключах dict, таких как начало и конец, но когда у вас их нет, у вас есть ошибка ... вам нужно проверить, есть ли у вашего dict ключ или нет. вы можете сделать это: если some_need_key в name_of_dict - person Konstantin Kozlenko; 12.07.2018
comment
Ваш примерный код не проходит проверку mypy. Реализация функции и ее вызовы не были виноваты, объявления подсказки типа. Не имело значения, что ключи отсутствовали (вопрос не в этом). (Ваш код по-прежнему производит Incompatible return value type (got "Tuple[Union[str, int], Union[str, int]]", expected "Tuple[int, int]"), и добавляет Dict entry 0 has incompatible type "str": "List[int]"; expected "str": "Union[str, int]" и Dict entry 1 has incompatible type "str": "List[int]"; expected "str": "Union[str, int]", потому что вы используете списки). - person Martijn Pieters; 12.07.2018