简体   繁体   中英

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

The intention is to overload the function and allow for multiple types of input, with user-defined coherent output.

I thus set a Type[TypeVar] of str or datetime.date (second function argument, with default value =str ) where the function would output the relevant TypeVar .

The following is the basic function (that I would further extend once this version is fixed):

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 gives error on the return statements (the TypeVar doesn't seem to work as I would have expected):

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

Any ideas? Is there a better way to write this code with proper type annotation?

The issue here is that mypy does not understand expressions of the form some_type is str or type(some_value) is str . You need to do either issubclass(some_type, str) or isinstance(some_value, str) instead.

That said, it would be more cleaner in this case to just make two different functions instead:

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

This ends up being fewer characters for your users to type since they don't need to keep including out_format=date or out_format=str everywhere. It's also less misleading: your original function doesn't actually always return a str, so calling it date2str is kind of confusing.

It would also probably be a good idea to just delete normalize_date entirely: datetime is a subclass of date, which means it's valid to use a datetime in any place that expects just a date. This means there really shouldn't be a need to explicitly convert a datetime into a date

For example, the following two prints would do the exact same thing (and would type check, according to mypy):

from datetime import datetime

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM