我有一个辅助函数,可以将
%Y-%m-%d %H:%M:%S
格式的字符串转换为 datetime.datetime
:
def ymdt_to_datetime(ymdt: str) -> datetime.datetime:
return datetime.datetime.strptime(ymdt, '%Y-%m-%d %H:%M:%S')
我可以验证函数本身中的
ymdt
格式,但使用自定义对象作为参数的类型提示会更有用,例如
from typing import NewType, Pattern
ymdt_pattern = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]'
YmdString = NewType('YmdString', Pattern[ymdt_pattern])
def ymdt_to_datetime(ymdt: YmdString)...
我是不是走错了兔子洞? 这应该是
mypy
或其他地方的问题吗? 或者这可以通过当前的类型提示实现(3.61)来完成吗?
不幸的是,目前类型无法静态验证您的字符串是否与精确格式匹配。这部分是因为在编译时检查给定变量可以保存的确切值非常难以实现(事实上,在某些情况下是 NP 难的),部分是因为面对用户输入等问题,该问题变得不可能。因此,这个功能不太可能在不久的将来添加到 mypy 或 Python 类型生态系统中(如果有的话)。
一个潜在的解决方法是利用
NewType
,并仔细控制何时构建该格式的字符串。也就是说,你可以这样做:
from typing import NewType
YmdString = NewType('YmdString', str)
def datetime_to_ymd(d: datetime) -> YmdString:
# Do conversion here
return YmdStr(s)
def verify_is_ymd(s: str) -> YmdString:
# Runtime validation checks here
return YmdString(s)
如果您仅使用此类函数来引入
YmdString
类型的值并进行测试以确认您的“构造函数”正常工作,则您可以在编译时或多或少安全地区分字符串和 YmdString
。然后,您需要设计程序以最大程度地减少调用这些函数的频率,以避免产生不必要的开销,但希望这不会太繁重。
🌷🌷🌷🌷🌷
好吧,五年后的今天,答案是是,至少如果您愿意使用第三方库并装饰您想要在运行时检查的函数:
$ pip install beartype
import re
from typing import Annotated # python 3.9+
from beartype import beartype
from beartype.vale import Is
YtdString = Annotated[str, Is[lambda string: re.match('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]', string) is not None]]
@beartype
def just_print_it(ytd_string: YtdString) -> None:
print(ytd_string)
> just_print_it("hey")
BeartypeCallHintParamViolation: @beartyped just_print_it() parameter ytd_string='hey' violates type hint typing.Annotated[str, Is[<lambda>]], as 'hey' violates validator Is[<lambda>]:
False == Is[<lambda>].
> just_print_it("2022-12-23 09:09:23")
2022-12-23 09:09:23
> just_print_it("2022-12-23 09:09:2")
BeartypeCallHintParamViolation: @beartyped just_print_it() parameter ytd_string='2022-12-23 09:09:2' violates type hint typing.Annotated[str, Is[<lambda>]], as '2022-12-23 09:09:2' violates validator Is[<lambda>]:
False == Is[<lambda>].
请注意,我使用的是最初包含在问题中的非常不完美的正则表达式模式,尚未准备好用于生产。
然后,一个充满希望的提示:
beartype
的维护者正在努力开发自动导入钩子,这将消除为了实现上述目的而对装饰函数的需要。
使用类型提示在 Python 中不执行任何操作,而是充当静态检查器中类型的指示。它并不意味着执行任何操作,只是注释一种类型。
您无法进行任何验证,您所能做的就是使用类型提示和检查器来确保传入的参数实际上是
str
类型。