[英]How to help mypy understand “if isinstance else” structure?
我使用一种简单的方法来处理可以是字符串或字符串列表的参数。 它故意对错误没有鲁棒性,但却是一种快速的方法。
该方法在普通的Python中可以正常工作,但是mypy不能很好地处理其类型并引发错误:
def dosomething(ext: Union[str, Iterable[str]] = ".txt"):
exts: Tuple[str, ...] = (ext, ) if isinstance(ext, str) else ext
错误: Incompatible types in assignment (expression has type "object", variable has type "Tuple[str, ...]")
调查此问题,我发现mypy无法使用if isinstance else结构减少可用的类型选项:
def dosomething(ext: Union[str, Iterable[str]] = ".txt"):
exts = (ext, ) if isinstance(ext, str) else ext
reveal_type(exts) # Revealed type is 'builtins.object'
看到mypy退回到object
对我来说是一个惊喜,但是我怀疑这可能是因为str
也是Iterable[str]
。
我想找到一种方法来避免这种意外情况,方法是在保持简单性的同时帮助mypy。
这归结为mypy如何为条件表达式推断类型的问题。 在简单的上下文中,表达式a if predicate else b
推断为a
和b
的超类型。 在str
和Iterable[str]
的情况下,这是builtins.object
。
x = reveal_type(1 if bool() else "str")
# Revealed type is 'builtins.object'
一个例外是,如果mypy可以将谓词解析为True或False,则将类型缩小为正确的分支:
x = reveal_type(1 if True else "str")
# Revealed type is 'builtins.int'
有人希望mypy可以将isinstance
检查解析为True或False,但是似乎尚未实现。 我认为这将是一个非常合理的功能要求。
但是,我们可以利用条件表达式类型的一个不错的功能,那就是它可以识别上下文。 因此,如果在期望使用其他类型的上下文中使用条件表达式,并且条件的两端都满足该类型,则类型检查将通过。 这已经讨论过这里的联盟类型的范围内,但在你的情况下,两个分支满足Iterable[str]
exts: Iterable[str] = (ext, ) if isinstance(ext, str) else ext
因此,关键只是明确指定exts
的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.