Python类型:通过基类参数缩小输出子类实例的范围



如果没有例子,我发现这很难描述。

from typing import List, Type, Optional, cast
class Base():
kind = 'base'
class Child1(Base):
kind = 'child1'
class Child2(Base):
kind = 'child2'
class Child3(Base):
kind = 'child3'
def find_in_list(lst: List[Base], SearchClass: Type[Base]): # Return Optional[??]
for obj in lst: # type: Base
if obj.kind == SearchClass.kind:
return obj
return None
lst = [Child1(), Child2(), Child3()]
def func2(c: Child2) -> None:
assert isinstance(c, Child2)
res2_opt: Optional[Child2] = find_in_list(lst, Child2)
if res2_opt:
func2(res2_opt)

def func3(c: Child3) -> None:
assert isinstance(c, Child3)
res3_opt: Optional[Child3] = find_in_list(lst, Child2) # Should be Error!
if res3_opt:
func3(res3_opt) # Is AssertionError

由于find_in_list的返回类型过于开放,mypy并不认为这有什么问题,但它在运行时正确地命中了断言错误。我尝试了-> Optional[SearchClass],但它(正确地(没有将其识别为一种类型。

应该可以缩小find_in_list的返回类型的范围,以与SearchClass相同或相同的方式进行参数化,这样,如果传入Child2作为参数,则可以将输出限制为Optional[Child2]。如何做到这一点?

您应该使用一个使用TypeVar的Generic函数,并强制转换返回值:

from typing import TypeVar, cast
T = TypeVar('T', bound=Base)
def find_in_list(lst: List[Base], SearchClass: Type[T]) -> Optional[T]:
for obj in lst:
if obj.kind == SearchClass.kind:
return cast(T, obj)
return None

然后:

res3_opt: Optional[Child3] = find_in_list(lst, Child2)
# Mypy: Incompatible types in assignment (expression has type "Optional[Child2]", 
# variable has type "Optional [Child3]")

最新更新