如何缩小工会名单?
How to narrow a list of unions?
我有一个 list[A | B]
类型的变量,它可以包含一个混合列表(如 [A(), B(), A()]
)。
如果我后来遇到一些极端情况并且我想确保所有元素实际上都是 A
类型,我可以 assert isinstance
在 for
循环中:
def f(mylist: list[A | B]):
...
...
for el in mylist:
assert isinstance(el, A)
# Now, I'm sure that mylist is actually `list[A]`
# How do I tell that to the type checker?
在 for
循环之后,如果我 reveal_type(mylist)
它仍然显示 list[A|B]
。我也尝试了 assert all(isinstance(el, A) for el in mylist)
而不是显式循环,但 mypy
仍然无法缩小它。这可能吗?或者我必须在这里使用 cast
吗?
Or do I have to use cast here?
使用 Python 3.10 可以缩小列表范围的 cast
的唯一替代方法是使用 TypeGuard,此代码:
from typing import TypeGuard
def is_str_list(val: list[int | str]) -> TypeGuard[list[str]]:
"""Determines whether all objects in the list are strings"""
return all(isinstance(x, str) for x in val)
def is_int_list(val: list[int | str]) -> TypeGuard[list[int]]:
"""Determines whether all objects in the list are ints"""
return all(isinstance(x, int) for x in val)
def f(mylist: list[int | str]):
if is_str_list(mylist):
reveal_type(mylist)
elif is_int_list(mylist):
reveal_type(mylist)
reveal_type(mylist)
缩小列表的类型而不使用 cast
:
narrow_collection.py:17: note: Revealed type is "builtins.list[builtins.str]"
narrow_collection.py:21: note: Revealed type is "builtins.list[builtins.int]"
narrow_collection.py:24: note: Revealed type is "builtins.list[Union[builtins.int, builtins.str]]"
我有一个 list[A | B]
类型的变量,它可以包含一个混合列表(如 [A(), B(), A()]
)。
如果我后来遇到一些极端情况并且我想确保所有元素实际上都是 A
类型,我可以 assert isinstance
在 for
循环中:
def f(mylist: list[A | B]):
...
...
for el in mylist:
assert isinstance(el, A)
# Now, I'm sure that mylist is actually `list[A]`
# How do I tell that to the type checker?
在 for
循环之后,如果我 reveal_type(mylist)
它仍然显示 list[A|B]
。我也尝试了 assert all(isinstance(el, A) for el in mylist)
而不是显式循环,但 mypy
仍然无法缩小它。这可能吗?或者我必须在这里使用 cast
吗?
Or do I have to use cast here?
使用 Python 3.10 可以缩小列表范围的 cast
的唯一替代方法是使用 TypeGuard,此代码:
from typing import TypeGuard
def is_str_list(val: list[int | str]) -> TypeGuard[list[str]]:
"""Determines whether all objects in the list are strings"""
return all(isinstance(x, str) for x in val)
def is_int_list(val: list[int | str]) -> TypeGuard[list[int]]:
"""Determines whether all objects in the list are ints"""
return all(isinstance(x, int) for x in val)
def f(mylist: list[int | str]):
if is_str_list(mylist):
reveal_type(mylist)
elif is_int_list(mylist):
reveal_type(mylist)
reveal_type(mylist)
缩小列表的类型而不使用 cast
:
narrow_collection.py:17: note: Revealed type is "builtins.list[builtins.str]"
narrow_collection.py:21: note: Revealed type is "builtins.list[builtins.int]"
narrow_collection.py:24: note: Revealed type is "builtins.list[Union[builtins.int, builtins.str]]"