如何注释 class 对象(而不是 class 实例)的类型?

How to annotate a type that's a class object (instead of a class instance)?

注释需要 class 对象而不是 class 实例的函数参数的正确方法是什么?

在下面的示例中,some_class 参数应该是一个类型实例(这是一个 class),但这里的问题是 type 太宽泛了:

def construct(some_class: type, related_data:Dict[str, Any]) -> Any:
    ...

some_class 需要一组特定类型对象的情况下,使用 type 根本没有帮助。 typing 模块可能需要一个 Class 泛型来执行此操作:

def construct(some_class: Class[Union[Foo, Bar, Baz]], related_data:Dict[str, Any]) -> Union[Foo, Bar, Baz]:
    ...

在上面的例子中,some_classFooBarFazclass,不是它的一个实例。它们在 class 树中的位置无关紧要,因为 some_class: Class[Foo] 也应该是有效的情况。因此,

# classes are callable, so it is OK
inst = some_class(**related_data)

# instances does not have __name__
clsname = some_class.__name__

# an operation that only Foo, Bar and Baz can perform.
some_class.a_common_classmethod()

mypy、pytype、PyCharm等应该都可以

如何使用当前实现(Python 3.6 或更早版本)完成此操作?

要注释 class 的对象,请使用 typing.Type。例如,这将告诉类型检查器 some_class 是 class Foo 或其任何子 classes:

from typing import Type
class Foo: ...
class Bar(Foo): ...
class Baz: ...
some_class: Type[Foo]
some_class = Foo # ok
some_class = Bar # ok
some_class = Baz # error
some_class = Foo() # error

注意 Type[Union[Foo, Bar, Baz]]Union[Type[Foo], Type[Bar], Type[Baz]] 是完全等价的。

如果 some_class 可以是多个 class 中的任何一个,您可能想让它们都继承自相同的基础 class,并使用 Type[BaseClass] .注意现在继承必须是非虚拟的(mypy对虚拟继承的支持是being discussed)。

已编辑以确认允许 Type[Union[...