类型提示中的子类

我希望允许使用 Python3的类型提示接受某个类的子类。例如:

class A:
pass


class B(A):
pass


class C(A):
pass


def process_any_subclass_type_of_A(cls: A):
if cls == B:
# do something
elif cls == C:
# do something else

现在输入以下代码:

process_any_subclass_type_of_A(B)

我得到一个 PyCharm IDE 提示“预期类型 A,得到类型[ B ]代替。”

如何在这里更改类型提示以接受 A 的任何子类型?

根据 PEP 484(“其类型是特定参数类型的子类型的表达式也被接受用于该参数。”),我明白我的解决方案 (cls: A)应该工作?

74524 次浏览

当您指定 cls: A时,您说的是 cls期望 例子的类型为 A。将 cls指定为类型 A(或其子类型)的类对象的类型提示使用 typing.Type

from typing import Type
def process_any_subclass_type_of_A(cls: Type[A]):
pass

从 < a href = “ http://mypy.readthedocs.io/en/best/kind _ of _ typees.html # The-type-of-class-Objects”rel = “ noReferrer”> 类对象的类型 :

有时,您希望讨论从 给定的类。这可以拼写为 Type[C],其中 C是一个类 换句话说,当 C是类的名称时,使用 C来注释 参数声明该参数是 C的实例(或者是 子类 C) ,但使用 Type[C]作为参数注释声明 参数是从 C派生的类对象(或者 C本身)。

如果我们查看 typing模块中的 Type描述,就会看到这些文档:

一种可用于对类对象进行注释的特殊构造。

例如,假设我们有以下类:

 class User: ...  # Abstract base for User classes
class BasicUser(User): ...
class ProUser(User): ...
class TeamUser(User): ...

类参数的子类 用户并返回相应类的实例:

 U = TypeVar('U', bound=User)
def new_user(user_class: Type[U]) -> U:
user = user_class()
# (Here we could write the user object to a database)
return user


joe = new_user(BasicUser)

此时,类型检查器知道 joe 具有 BasicUser 类型。

基于此,我可以想象一个合成示例,它在 PyCharm 中重现了类型提示错误的问题。

from typing import Type, Tuple


class BaseClass: ...


class SubClass(BaseClass): ...
class SubSubClass(SubClass): ...


def process(model_instance: BaseClass, model_class: Type[BaseClass]) -> Tuple[BaseClass, BaseClass]:
""" Accepts all of the above classes """
return model_instance, model_class()




class ProcessorA:
@staticmethod
def proc() -> Tuple[SubClass, SubClass]:
""" PyCharm will show an error
`Expected type 'tuple[SubClass, SubClass]', got 'tuple[BaseClass, BaseClass]' instead` """
return process(SubClass(), SubClass)




class ProcessorB:
@staticmethod
def proc() -> Tuple[SubSubClass, SubSubClass]:
""" PyCharm will show an error
`Expected type 'tuple[SubSubClass, SubSubClass]', got 'tuple[BaseClass, BaseClass]' instead` """
return process(SubSubClass(), SubSubClass)

但是我们在 Type的文档中看到,这种情况可以通过使用带有 bound参数的 TypeVar来纠正。然后在将 BaseClass声明为类型的地方使用它。

from typing import TypeVar, Type, Tuple


class BaseClass: ...


B = TypeVar('B', bound=BaseClass)


class SubClass(BaseClass): ...
class SubSubClass(SubClass): ...


def process(model_instance: B, model_class: Type[B]) -> Tuple[B, B]:
""" Accepts all of the above classes """
return model_instance, model_class()




class ProcessorA:
@staticmethod
def proc() -> Tuple[SubClass, SubClass]:
return process(SubClass(), SubClass)




class ProcessorB:
@staticmethod
def proc() -> Tuple[SubSubClass, SubSubClass]:
return process(SubSubClass(), SubSubClass)

希望这对你有帮助。

如果希望函数接受 只有子类,应该使用 NewType https://docs.python.org/3/library/typing.html#newtype,因为 Type [ A ]也接受类本身,这并不总是需要。