类型提示和@singledispatch:如何以可扩展的方式包含 `Union[...]`?

ten*_*nni 6 python type-hinting single-dispatch

我正在重构一个将各种日期格式(即 ISO 8601 字符串、 、 等)转换datetime.datedatetime.datetimeUnix 时间戳的函数。

\n\n

我希望使用新函数@singledispatch而不是类型检查,但我不知道如何保留前一个函数的类型提示:

\n\n

旧功能:使用类型检查

\n\n
import datetime\nfrom typing import Union\n\n\nMyDateTimeType = Union[int, str, datetime.datetime, datetime.date, None]\n\n\n# How do I retain this functionality with @singledispatch?\n#                    \xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\xe2\xac\x87\xef\xb8\x8f\ndef to_unix_ts(date: MyDateTimeType = None) -> Union[int, None]:\n    """Convert various date formats to Unix timestamp..."""\n    if type(date) is int or date is None:\n        return date\n\n    if type(date) is str:\n        # Handle string argument...\n\n    elif type(date) is datetime.datetime:\n        # Handle datetime argument...\n\n    elif type(date) is datetime.date:\n        # Handle date argument...\n
Run Code Online (Sandbox Code Playgroud)\n\n

新功能:使用@singledispatch

\n\n
import datetime\nfrom functools import singledispatch\nfrom typing import Union\n\n\n@singledispatch\ndef to_unix_ts(date) -> Union[int, None]:\n    """Handle generic case (probably string type)..."""\n\n@to_unix_ts.register\ndef _(date: int) -> int:\n    return date\n\n\n@to_unix_ts.register\ndef _(date: None) -> None:\n    return date\n\n\n@to_unix_ts.register\ndef _(date: datetime.datetime) -> int:\n    return int(date.replace(microsecond=0).timestamp())\n\n\n# etc...\n
Run Code Online (Sandbox Code Playgroud)\n\n

我已经探索过构建支持的类型,如下所示:

\n\n
supported_types = [type for type in to_unix_ts.registry.keys()]\nMyDateTimeType = Union(supported_types)  # Example, doesn\'t work\n
Run Code Online (Sandbox Code Playgroud)\n\n

...这样它就可以通过未来的 @singledispatch 注册进行扩展,但我无法让它工作。

\n\n

如何以可扩展的方式Union[...]在函数中添加样式类型提示?@singledispatch

\n

Ben*_*ell 7

我想这就是你要找的。请注意,singledispatch需要register(type(None))而不是register(None). 它不支持register(Union[a, b]),但您可以将多个register装饰器应用于一个函数......

import datetime
from functools import singledispatch
from typing import Union

MyDateTimeType = Union[
    int,
    None,
    datetime.datetime,
    datetime.date
]

@singledispatch
def to_unix_ts(date: MyDateTimeType) -> Union[int, None]:
    raise NotImplementedError

@to_unix_ts.register(int)
@to_unix_ts.register(type(None))
def _(date: Union[int, None]) -> Union[int, None]:
    return date

@to_unix_ts.register(str)
def _(date: str):
    # Handle string argument...

@to_unix_ts.register(datetime.datetime)
def _(date: datetime.datetime):
    # Handle datetime argument...

@to_unix_ts.register(datetime.date)
def _(date: datetime.date):
    # Handle date argument...
Run Code Online (Sandbox Code Playgroud)