当值是 cls 的实例时,您可以注释返回类型吗?

问题描述:

给定一个带有用于初始化的辅助方法的类:

Given a class with a helper method for initialization:

class TrivialClass:
    def __init__(self, str_arg: str):
        self.string_attribute = str_arg

    @classmethod
    def from_int(cls, int_arg: int) -> ?:
        str_arg = str(int_arg)
        return cls(str_arg)

是否可以注释from_int方法的返回类型?

Is it possible to annotate the return type of the from_int method?

我尝试了 clsTrivialClass 但 PyCharm 将它们标记为未解析的引用,这在当时听起来很合理.

I'v tried both cls and TrivialClass but PyCharm flags them as unresolved references which sounds reasonable at that point in time.

使用泛型来表示你将返回一个 cls 的实例:>

Use a generic type to indicate that you'll be returning an instance of cls:

from typing import Type, TypeVar

T = TypeVar('T', bound='TrivialClass')

class TrivialClass:
    # ...

    @classmethod
    def from_int(cls: Type[T], int_arg: int) -> T:
        # ...
        return cls(...)

任何覆盖类方法但随后返回父类(TrivialClass 或仍然是祖先的子类)的实例的子类都将被检测为错误,因为工厂方法被定义为返回 cls 类型的实例.

Any subclass overriding the class method but then returning an instance of a parent class (TrivialClass or a subclass that is still an ancestor) would be detected as an error, because the factory method is defined as returning an instance of the type of cls.

bound 参数指定 T 必须是 TrivialClass 的(子类);因为在定义泛型时该类尚不存在,所以您需要使用 forward 引用(带有名称的字符串).

The bound argument specifies that T has to be a (subclass of) TrivialClass; because the class doesn't yet exist when you define the generic, you need to use a forward reference (a string with the name).

请参阅注释实例和 PEP 484 的类方法部分.

注意:此答案的第一次修订提倡使用前向引用将类本身命名为返回值,但 issue 1212 使得使用泛型成为可能,更好的解决方案.

Note: The first revision of this answer advocated using a forward reference naming the class itself as the return value, but issue 1212 made it possible to use generics instead, a better solution.

从 Python 3.7 开始,当您使用 from __future__ import annotations,但是创建了一个TypeVar() 模块级别的对象不是注释.即使在 Python 3.10 中也是如此,它推迟了注释中的所有类型提示解析.

As of Python 3.7, you can avoid having to use forward references in annotations when you start your module with from __future__ import annotations, but creating a TypeVar() object at module level is not an annotation. This is still true even in Python 3.10, which defers all type hint resolution in annotations.