当value是cls的实例时,你能注释返回类型吗?

问题描述 投票:0回答:4

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

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
方法的返回类型?

我尝试了

cls
TrivialClass
,但 PyCharm 将它们标记为未解析的引用,这在当时听起来很合理。

python pycharm python-typing
4个回答
103
投票

从 Python 3.11 开始,您可以使用新的

typing.Self
对象。对于较旧的 Python 版本,您可以使用
typing-extensions
项目
:

获取相同的对象
try:
    from typing import Self
except ImportError:
    from typing_extensions import Self


class TrivialClass:
    # ...

    @classmethod
    def from_int(cls, int_arg: int) -> Self:
        # ...
        return cls(...)

请注意,在这种情况下您不需要注释

cls

警告:mypy 对

Self
类型的支持尚未发布;您需要等待0.991之后的下一个版本。 Pyright 已经支持了。

如果您等不及 Mypy 支持,那么您可以使用 generic type 来指示您将返回

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
的类型。

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

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


注意:此答案的第一次修订提倡使用前向引用 将类本身命名为返回值,但是issue 1212使得可以使用泛型来代替,这是一个更好的解决方案。

从 Python 3.7 开始,当您使用 from __future__ import annotations

 启动模块时,您
可以避免在注释中使用前向引用,但在模块级别创建
TypeVar()
对象不是注释。即使在 Python 3.10 中也是如此,它推迟了注释中的所有类型提示解析。


11
投票

从 Python 3.7 开始,您可以使用

__future__.annotations

from __future__ import annotations


class TrivialClass:
    # ...

    @classmethod
    def from_int(cls, int_arg: int) -> TrivialClass:
        # ...
        return cls(...)

编辑:你不能在不重写类方法的情况下子类化

TrivialClass
,但如果你不需要这个,那么我认为它比前向引用更简洁。


11
投票

在 Python 3.11 中,有一种更好的方法可以使用新的 Self 类型来做到这一点:

from typing import Self

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

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

这也适用于子类。

class TrivialSubClass(TrivialClasss):
    ...

TrivialSubclass.from_int(42)

IDE 显示返回类型

TrivialSubClass
而不是
TrivialClass

这在PEP 673中进行了描述。


7
投票

注释返回类型的一个简单方法是使用字符串作为类方法的返回值的注释:

# test.py
class TrivialClass:
  def __init__(self, str_arg: str) -> None:
    self.string_attribute = str_arg

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

这通过了 mypy 0.560 并且 python 没有错误:

$ mypy test.py --disallow-untyped-defs --disallow-untyped-calls
$ python test.py
© www.soinside.com 2019 - 2024. All rights reserved.