繁体   English   中英

类型提示返回 self 的 class 方法的返回值?

[英]Type hinting the return value of a class method that returns self?

如问题所述,我想输入提示self返回,例如:

class A:
  def foo(self) -> [what goes here?]:
    # do something
    return self

我已经尝试过的事情:

  1. 将其注释为A (在顶部添加from __future__ import annotations ):这意味着该方法返回一个实例化A() object,不一定是self
  2. 将其注释为Type[A]from typing import Type添加):这意味着返回的方法正在返回一个未实例化A ,它与self不相距甚远。
  3. 注释为Self (添加from typing_extensions import Self ):mypy 给出错误: Variable "typing_extensions.Self" is not valid as a type [valid-type]mypy(error)

可能有帮助的事情:将鼠标悬停在没有返回值注释的方法foo上, VScode提示显示 - Self@A ,我不明白但是,这绝对区分返回另一个实例化的 class A()和返回self .. 。 谢谢

我找不到任何与此密切相关的问题,因此将尝试解释。

“相同类型”对于类型检查意味着什么

好吧,这可能是“你不能,你不应该”的长形式。

类型检查旨在确认所有函数都使用正确的参数类型调用并返回预期类型。 我建议先阅读PEP483以更好地理解类型的概念。 假设您有以下内容:

s1 = ''.join(['a', 'b', 'c'])
s2 = ''.join(['a', 'b', 'c'])
assert s1 is not s2
assert s1 == s2

join以避免优化,但这是另一回事)。 他们是同一个object吗? 不, is not明确说明这一点(他们有不同的 memory 地址)。 但是只要你想要s1s2是否可以接受? 绝对是的。 您不会创建仅在s1上运行并使用is检查此事实的 function,对吗?

现在self作为对精确 object 的引用和作为任何A实例的self之间有什么区别 当我们谈论类型检查时,所有A实例都是完全等价且不可区分的。 它们具有相同的一组方法和属性(包括类型)。 我们可以问:“如果我们明确声明 object 是self实例而不仅仅是self类型,那么可以引入或移除哪些类型错误?” 我真的想不出任何。 如果你想要这个用于语义,请使用 docstring - 类型不应该被滥用。 self object 与类型检查器的任何其他A()实例完全相同。

简单的解决方案:返回 class 实例

您的第一个代码示例几乎没问题。 将 return 注释为A以告知它返回 class A实例,它将适用于最终的 class:

class A:
    def foo(self) -> A:
        return self

然而,这种方法有一个缺点(在 PEP673 中关于Self类型有很好的解释):

class AChild(A):
    pass

# mypy
reveal_type(AChild().foo())  # N: revealed type is "__main__.A"

如果您在foo中创建新A并将其返回,那么这种方法是完美的。 如果您return self - 它是有效的,但不准确。 这就是为什么我们需要Self类型。

Self类型太现代

截至目前, mypy不支持PEP673中描述的Self类型,因此它失败并显示一条神秘消息。 但是,您在第三个示例中的用法是完全有效的,并且在类型检查器中实现后将起作用(请参阅 PEP 的“动机”部分中的第 5 个代码块)。

以下是您如何使用Self (假设python=3.11不打扰typing_extensions和不久的将来mypy支持):

from typing import Self

class A:
    def foo(self) -> Self:
        return self

class AChild(A):
    pass

# mypy
reveal_type(AChild().foo())  # N: revealed type is "__main__.AChild"
reveal_type(A().foo())  # N: revealed type is "__main__.A"

这很棒,但现在不起作用。 请注意,其他检查器(即pyrightpyre )对此提供支持。

在不使用的情况下实现Self类型

但是,您可以使用几行代码(和python >= 3.7 ,AFAIR)准确地模仿Self

from typing import TypeVar

_Self = TypeVar('_Self', bound='A')

class A:
    def foo(self: _Self) -> _Self:
        return self

class AChild(A):
    pass

# mypy
reveal_type(AChild().foo())  # N: revealed type is "__main__.AChild"
reveal_type(A().foo())  # N: revealed type is "__main__.A"

现在这有效。 所有子类都将返回它们的 class 实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM