【问题标题】:How to annotate a type that's a class object (instead of a class instance)?如何注释作为类对象(而不是类实例)的类型?
【发布时间】:2017-05-16 00:29:31
【问题描述】:

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

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

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

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

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

在上面的示例中,some_classFooBarFaz 类,而不是它的实例。它们在类树中的位置无关紧要,因为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 或更早版本)来做到这一点?

【问题讨论】:

  • 如果您需要比type 更具体,请引入元类或抽象基类。
  • @jonrsharpe - 我相信元类可以解决问题,但我在 Python 中还没有达到这个水平。随着 3.6 中变量注解的引入(包括一个 ClassVar 来区分实例变量和类变量),我想知道当有这么多注解类实例的方法时,为什么要使用 type 来注解类对象。也许我必须等待未来的更新或食谱:)。
  • 看来我将不得不依赖typing.Type 并执行Foo = TypeVar['Foo', bond=Bar] 之类的操作,其中Bar 是ABC,那么,以上面的示例为例:def construct(some_class: Type[Foo], ...) -> Foo。我特别不喜欢使用TypeVar,但它似乎是唯一的方法......

标签: python annotations type-hinting python-typing


【解决方案1】:

要注释作为类的对象,请使用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

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

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

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

【讨论】:

  • 使用Union[Type[Class], Type[ClassB]]Type[Union[ClassA, ClassB]] 更安全吗?我会默认为第一选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-24
  • 2023-02-16
  • 2013-04-01
  • 2015-05-28
  • 1970-01-01
  • 2021-02-12
  • 2013-10-22
相关资源
最近更新 更多