Python 键入:通过基本 class 参数缩小输出 subclass 实例的范围
Python typing: Narrowing the scope of output subclass instance by base class parameter
如果没有例子,我发现这很难描述。
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
的return类型太开放了,mypy不认为这有什么问题,但它在运行时正确地命中了断言错误。我试过 -> Optional[SearchClass]
,但它(正确地)没有将其识别为类型。
应该可以缩小 find_in_list
的 return 类型的范围,以与 SearchClass
相同或相同的方式进行参数化,这样如果你通过in Child2
作为参数,可以限制输出为Optional[Child2]
。如何做到这一点?
您应该使用 TypeVar
的通用函数并转换 return 值:
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]")
如果没有例子,我发现这很难描述。
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
的return类型太开放了,mypy不认为这有什么问题,但它在运行时正确地命中了断言错误。我试过 -> Optional[SearchClass]
,但它(正确地)没有将其识别为类型。
应该可以缩小 find_in_list
的 return 类型的范围,以与 SearchClass
相同或相同的方式进行参数化,这样如果你通过in Child2
作为参数,可以限制输出为Optional[Child2]
。如何做到这一点?
您应该使用 TypeVar
的通用函数并转换 return 值:
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]")