mypy жалуется: аннотация типа функции с типом [TypeVar ['T', str, date]] и выводом T: несовместимый тип возвращаемого значения (получено "str", ожидается "date") - PullRequest
0 голосов
/ 04 февраля 2020

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

Таким образом, я установил Type[TypeVar] из str или datetime.date (второй аргумент функции со значением по умолчанию =str), где функция будет выводить соответствующую TypeVar.

Ниже приведена базовая функция c (которую я буду расширять, как только эта версия будет исправлена):

from typing import TypeVar, Type
from datetime import date, datetime

DateOutType = TypeVar('DateOutType', str, date)

def date2str(t: date, out_format: Type[DateOutType]=Type[str]) -> DateOutType:
    ''' Converts datetime.date to string (YYYY-MM-DD) or datetime.date output.
    '''
    if out_format is str:
        return t.strftime('%Y-%m-%d')
    elif isinstance(t, datetime):
        return t.date()
    else:
        return t

# Usage example:

dt = datetime.now()

res = date2str(dt, out_format=date)
assert type(res) == date

res = date2str(dt.date(), out_format=str)
assert type(res) == str

mypy выдает ошибку в операторах return (TypeVar, похоже, не работает так, как я ожидал):

first return statement: error: Incompatible return value type (got "str", expected "date")
second return statement: error: Incompatible return value type (got "date", expected "str")
third return statement: error: Incompatible return value type (got "date", expected "str")

Есть идеи? Есть ли лучший способ написать этот код с правильной аннотацией типа?

1 Ответ

1 голос
/ 06 февраля 2020

Проблема в том, что mypy не понимает выражения вида some_type is str или type(some_value) is str. Вместо этого вам нужно сделать либо issubclass(some_type, str), либо isinstance(some_value, str).

Тем не менее, в этом случае было бы более понятным сделать вместо этого две разные функции:

def date_to_str(t: date) -> str:
    return t.strftime('%Y-%m-%d')

def normalize_date(t: date) -> date:
    if isinstance(t, datetime):
        return t.date()
    return t

Это заканчивается до того, как ваши пользователи будут набирать меньше символов, так как им не нужно постоянно указывать out_format=date или out_format=str. Это также меньше вводит в заблуждение: ваша оригинальная функция на самом деле не всегда возвращает str, поэтому вызов ее date2str немного запутывает.

Вероятно, было бы неплохо просто полностью удалить normalize_date: datetime является подклассом даты, что означает, что допустимо использовать datetime в любом месте, которое ожидает только дату. Это означает, что на самом деле не должно быть необходимости явно преобразовывать дату и время в дату

Например, следующие два отпечатка будут делать одно и то же (и проверять тип, согласно mypy):

from datetime import datetime

dt = datetime.now()
print(date_to_str(dt))
print(date_to_str(normalize_date(dt)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...