我正在重构一个函数,该函数将各种日期格式(即 ISO 8601 字符串、
datetime.date
、
datetime.datetime
等)转换为 Unix 时间戳。
我希望新函数使用
@singledispatch
而不是类型检查,但我不知道如何保留以前函数的类型提示:
旧函数:使用类型检查
import datetime
from typing import Union
MyDateTimeType = Union[int, str, datetime.datetime, datetime.date, None]
# How do I retain this functionality with @singledispatch?
# ⬇️⬇️⬇️⬇️⬇️⬇️⬇️
def to_unix_ts(date: MyDateTimeType = None) -> Union[int, None]:
"""Convert various date formats to Unix timestamp..."""
if type(date) is int or date is None:
return date
if type(date) is str:
# Handle string argument...
elif type(date) is datetime.datetime:
# Handle datetime argument...
elif type(date) is datetime.date:
# Handle date argument...
新函数:使用
@singledispatch
import datetime
from functools import singledispatch
from typing import Union
@singledispatch
def to_unix_ts(date) -> Union[int, None]:
"""Handle generic case (probably string type)..."""
@to_unix_ts.register
def _(date: int) -> int:
return date
@to_unix_ts.register
def _(date: None) -> None:
return date
@to_unix_ts.register
def _(date: datetime.datetime) -> int:
return int(date.replace(microsecond=0).timestamp())
# etc...
我已经探索过构建支持的类型,如下所示:| ||...这样它就可以通过未来的@singledispatch 注册进行扩展,但我无法让它工作。
supported_types = [type for type in to_unix_ts.registry.keys()]
MyDateTimeType = Union(supported_types) # Example, doesn't work
如何以可扩展的方式在
函数中添加
Union[...]
样式类型提示?
@singledispatch
function in an extensible way?
可以使用
typing.overload
为的
@singledispatch
函数提供干净且可扩展的类型提示。
overload
允许为同一函数定义多个类型签名,而实际实现由运行时调度处理。
以下是使用
overload
重构函数的方法:
import datetime
from functools import singledispatch
from typing import Union, overload
@overload
def to_unix_ts(date: int) -> int:
...
@overload
def to_unix_ts(date: None) -> None:
...
@overload
def to_unix_ts(date: datetime.datetime) -> int:
...
@overload
def to_unix_ts(date: datetime.date) -> int:
...
@overload
def to_unix_ts(date: str) -> int:
...
@to_unix_ts.register
def _(date: int) -> int:
return date
@to_unix_ts.register
def _(date: None) -> None:
return date
@to_unix_ts.register
def _(date: datetime.datetime) -> int:
return int(date.replace(microsecond=0).timestamp())
@to_unix_ts.register
def _(date: datetime.date) -> int:
# 处理日期参数...
pass
@to_unix_ts.register
def _(date: str) -> int:
# 处理字符串参数...
pass
说明:
-
@overload
装饰器: 我们为to_unix_ts
定义了多个@overload
装饰的函数,每个装饰器都指定了特定类型的参数和返回值。这些都不会定义实现。 -
单一实现:
@singledispatch
和它的注册处理实际实现,就像之前一样。 -
类型提示改进:
@overload
装饰器告诉类型检查器,to_unix_ts
可以接受不同的类型并返回相应的类型,从而提供准确的类型提示,而无需Union
。
现在,当使用
to_unix_ts
时,类型检查器将使用
@overload
签名来推断正确的类型,并且
@singledispatch
机制将在运行时处理正确的实现。这提供了类型安全性和可扩展性。