在 Python 中进行类型提示时,我有两个选项将表达式标记为某种类型:
from typing import cast
foo = cast(str, expression)
bar = expression # type: str
两者有什么区别?
我的印象是有时使用
cast
有效,而有时我必须使用注释。但我还没有想出一个模式。不幸的是,我目前手头没有一个可以工作但另一个不能工作的代码示例。
# type: ignore
表示“请消除此行中出现的任何与类型相关的错误”。
cast(TYPE, EXPR)
的意思是“我知道你认为 X 的 EXPR 类型,但我希望你假设该类型实际上是 TYPE,好吗?”
当您遇到类型检查器的某些无法解决的限制时,您通常会使用
# type: ignore
。例如,假设您尝试导入一些没有存根或类型定义的第三方库。在这种情况下,做:
# Results in errors like"
# error: No library stub file for module 'library_with_no_hints'
import library_with_no_hints
...通常会导致错误。但您可以使用
# type: ignore
来消除该错误:
import library_with_no_hints # type: ignore
当您有额外的带外信息时,您通常会使用
cast
,类型检查器不知道某些类型 X 实际上只是 Y。例如:
def parse_config(assume_normalized: bool, thing: List[Union[int, str]]) -> List[int]:
if assume_normalized:
# The type-checker thinks that 'thing' is a List[Union[int, str]];
# we now force it to assume it's really a List[int] instead.
return cast(List[int], thing)
else:
output = []
for item in thing:
if isinstance(item, int):
output.append(item)
else:
output.append(parse(item))
return output
您通常会在以下情况下看到强制转换:a)您正在处理大量反序列化/序列化样式代码,并且需要将过于广泛的类型向下转换为更具体的类型,b)您正在使用多重继承做奇怪的事情,或者c )你的代码设计得很糟糕,你已经把自己逼到了墙角。
我个人几乎从不使用强制转换——如果可以的话,我会尝试避免它们,如果不能,我将至少使用 isinstance 检查等,这样如果我的假设最终是错误的,我的代码将在运行时崩溃。
(我也尝试忽略
# type: ignore
,但有时它们最终会成为一种必要的邪恶/可以帮助您解决类型检查器中的限制。)
如果您计划在代码库中使用类型忽略或强制转换,您还应该考虑配置类型检查器,以便当您在不必要的地方使用它们时它会向您发出警告。
例如,使用 mypy,您可以传入
--warn-unused-ignores
和 --warn-unused-casts
标志。
如果您遇到过这个问题,值得注意的是,有更好的方法将表达式转换为某种类型:
foo: str = expression
通过这种方法,您可以避免在运行时导入和调用
cast
进行静态类型检查。