如何注释类型实例(而不是类实例)?

Gom*_* A. 9 python annotations type-hinting

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

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

def construct(some_class: type, related_data:Dict[str, Any]) -> Any:
    ...
Run Code Online (Sandbox Code Playgroud)

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

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

在上面的例子中,some_classFoo,BarFaz类,而不是它的一个实例.它们在类树中的位置无关紧要,因为它some_class: Class[Foo]也应该是一个有效的案例.因此,

# classes are callable, so it is OK
inst = some_class(**related_data)
Run Code Online (Sandbox Code Playgroud)

要么

# instances does not have __name__
clsname = some_class.__name__
Run Code Online (Sandbox Code Playgroud)

要么

# an operation that only Foo, Bar and Baz can perform.
some_class.a_common_classmethod()
Run Code Online (Sandbox Code Playgroud)

应该是mypy,pytype,PyCharm等等.

如何通过当前的实现(Python 3.6或更早版本)来完成?

max*_*max 19

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

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
Run Code Online (Sandbox Code Playgroud)

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

如果some_class可以是许多类中的任何一个,您可能希望使它们都从相同的基类继承,并使用Type[BaseClass].请注意,继承现在必须是非虚拟的(正在讨论 mypy对虚拟继承的支持).

编辑确认Type[Union[...是允许的.

  • 从 Python 3.9 开始,“typing.Type”已被弃用,因为您现在可以使用“type[MyClass]”(尽管 mypy 有问题,但对 Pylance 来说没问题)。Python 3.10 引入了带有“|”的 Union 表达式。所以现在可以写`type[ClassA] | 类型[ClassB]`或`类型[ClassA | B 类]`。 (17认同)
  • 使用“Union[Type[Class], Type[ClassB]]”或“Type[Union[ClassA, ClassB]]”更安全吗?我会默认第一个选择。 (2认同)