Каков рекомендуемый способ аннотировать объекты даты и времени? - PullRequest
3 голосов
/ 14 апреля 2020

Предположим, у меня есть функция, которая принимает две даты и возвращает разницу в секундах:

import datetime


def diff(d1: datetime.datetime, d2: datetime.datetime) -> float:
    return (d2 - d1).total_seconds()


if __name__ == '__main__':
    d1 = datetime.datetime.now()
    d2 = datetime.datetime.now(datetime.timezone.utc)
    print(diff(d1, d2))

mypy говорит мне, что все в порядке:

$ python3.8 -m mypy test.py
Success: no issues found in 1 source file

Но я получаю ошибку типа:

TypeError: can't subtract offset-naive and offset-aware datetimes

Причина четко указана в сообщении об ошибке. Типовая аннотация была недостаточно хороша.

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

1 Ответ

0 голосов
/ 15 апреля 2020

Одним из возможных решений является использование TypeVar, NewType и приведение:

import datetime
from typing import NewType, TypeVar, cast

NDT = NewType("NDT", datetime.datetime)  # non-aware datetime
ADT = NewType("ADT", datetime.datetime)  # timezone aware datetime
DatetimeLike = TypeVar("DatetimeLike", NDT, ADT)


def diff(d1: DatetimeLike, d2: DatetimeLike) -> float:
    return (d2 - d1).total_seconds()


if __name__ == "__main__":
    d1: NDT = cast(NDT, datetime.datetime.now())
    d2: ADT = cast(ADT, datetime.datetime.now(datetime.timezone.utc))

    # Fails with:
    #    error: Value of type variable "DatetimeLike" of "diff" cannot be "datetime"
    # You have to use either NDT or ADT
    print(diff(d1, d2))

Мне не нравится в этом решении, что вы должны использовать cast и что сообщение об ошибке менее ясно, чем было до этого.

...