pycharm 当值是cls的示例时,你能注解返回类型吗?

omvjsjqw  于 2023-01-30  发布在  PyCharm
关注(0)|答案(4)|浏览(156)

给定一个类,它有一个用于初始化的helper方法:

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方法的返回类型?
我尝试了clsTrivialClass,但是PyCharm将它们标记为未解析的引用,这在当时听起来是合理的。

h7wcgrx3

h7wcgrx31#

从Python 3.11开始,你可以使用新的typing.Self对象,对于旧的Python版本,你可以使用typing-extensions project来得到相同的对象:

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的支持,那么你可以使用一个 * 泛型类型 * 来表示你将返回一个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中也是如此,Python 3.10推迟了注解中所有类型提示的解析。

ddhy6vgd

ddhy6vgd2#

在Python 3.7中,可以使用__future__.annotations

from __future__ import annotations

class TrivialClass:
    # ...

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

编辑:如果不覆盖classmethod,你就不能子类化TrivialClass,但是如果你不需要这个,那么我认为它比前向引用更简洁。

gv8xihay

gv8xihay3#

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

# 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
68bkxrlz

68bkxrlz4#

在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中进行了说明。

相关问题