mypy 抱怨:带有 Type[TypeVar['T', str, date]] 和 T 输出的函数类型注释:不兼容 return 值类型(得到 "str",预期 "date")

mypy complains: function type annotation with Type[TypeVar['T', str, date]] and T output: Incompatible return value type (got "str", expected "date")

目的是重载函数并允许多种类型的输入,以及用户定义的连贯输出。

因此,我设置了 Type[TypeVar] of str or datetime.date(第二个函数参数,默认值=str),函数将输出相关的 TypeVar.

以下是基本功能(待此版本修复后我会进一步扩展):

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

有什么想法吗? 有没有更好的方法来使用正确的类型注释来编写此代码?

这里的问题是 mypy 不理解 some_type is strtype(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=dateout_format=str。它的误导性也更小:您的原始函数实际上并不总是 return 一个 str,所以称它为 date2str 有点令人困惑。

完全删除 normalize_date 也可能是个好主意:日期时间是日期的子类,这意味着在任何需要日期的地方使用日期时间都是有效的。这意味着确实不需要将日期时间显式转换为日期

例如,以下两个打印将做完全相同的事情(根据 mypy 将键入检查):

from datetime import datetime

dt = datetime.now()
print(date_to_str(dt))
print(date_to_str(normalize_date(dt)))