[英]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
我已经尝试过的事情:
A
(在顶部添加from __future__ import annotations
):这意味着该方法返回一个实例化A()
object,不一定是self
。Type[A]
( from typing import Type
添加):这意味着返回的方法正在返回一个未实例化A
,它与self
不相距甚远。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 地址)。 但是只要你想要s1
, s2
是否可以接受? 绝对是的。 您不会创建仅在s1
上运行并使用is
检查此事实的 function,对吗?
现在self
作为对精确 object 的引用和作为任何A
实例的self
之间有什么区别? 当我们谈论类型检查时,所有A
实例都是完全等价且不可区分的。 它们具有相同的一组方法和属性(包括类型)。 我们可以问:“如果我们明确声明 object 是self
实例而不仅仅是self
类型,那么可以引入或移除哪些类型错误?” 我真的想不出任何。 如果你想要这个用于语义,请使用 docstring - 类型不应该被滥用。 self
object 与类型检查器的任何其他A()
实例完全相同。
您的第一个代码示例几乎没问题。 将 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"
这很棒,但现在不起作用。 请注意,其他检查器(即pyright
和pyre
)对此提供支持。
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.