[英]Type hinting the return value of a class method that returns self?
as the questions describes, I wanna type hint a self
return, something like:如问题所述,我想输入提示self
返回,例如:
class A:
def foo(self) -> [what goes here?]:
# do something
return self
Things I already tried:我已经尝试过的事情:
A
( adding from __future__ import annotations
at the top ): this means the method returns an instantiated A()
object, not necessarily self
.将其注释为A
(在顶部添加from __future__ import annotations
):这意味着该方法返回一个实例化A()
object,不一定是self
。Type[A]
( adding from typing import Type
): this means the method is returning is returning an un-instantiated A
, which isnt remotely close to self
.将其注释为Type[A]
( from typing import Type
添加):这意味着返回的方法正在返回一个未实例化A
,它与self
不相距甚远。Self
( adding from typing_extensions import Self
): mypy gives an error: Variable "typing_extensions.Self" is not valid as a type [valid-type]mypy(error)
注释为Self
(添加from typing_extensions import Self
):mypy 给出错误: Variable "typing_extensions.Self" is not valid as a type [valid-type]mypy(error)
Things that might be of help : hovering over the method foo
with no annotations of a return value, VScode
hints shows - Self@A
, i dont understand it but, this definitely differentiates between returning another instantiated class A()
and returning self
... Thanks可能有帮助的事情:将鼠标悬停在没有返回值注释的方法foo
上, VScode
提示显示 - Self@A
,我不明白但是,这绝对区分返回另一个实例化的 class A()
和返回self
.. 。 谢谢
I can't find any question that covers this closely, so will try to explain.我找不到任何与此密切相关的问题,因此将尝试解释。
Well, probably this is the long form of "you can't, and you shouldn't".好吧,这可能是“你不能,你不应该”的长形式。
Type checking aims to confirm that all functions are called with proper argument types and return expected types.类型检查旨在确认所有函数都使用正确的参数类型调用并返回预期类型。 I suggest to read PEP483 first to understand concept of type better.我建议先阅读PEP483以更好地理解类型的概念。 Suppose you have the following:假设您有以下内容:
s1 = ''.join(['a', 'b', 'c'])
s2 = ''.join(['a', 'b', 'c'])
assert s1 is not s2
assert s1 == s2
( join
to avoid optimization, but it's another story). ( join
以避免优化,但这是另一回事)。 Are they the same object?他们是同一个object吗? No, is not
clearly states this (they have different memory addresses).不, is not
明确说明这一点(他们有不同的 memory 地址)。 But will s2
be acceptable whenever you want s1
?但是只要你想要s1
, s2
是否可以接受? Definitely yes.绝对是的。 You will not create a function that operates only on s1
and checks this fact with is
, right?您不会创建仅在s1
上运行并使用is
检查此事实的 function,对吗?
Now what is the difference between self
as reference to exact object and self
as any A
instance?现在self
作为对精确 object 的引用和作为任何A
实例的self
之间有什么区别? When we talk about type checking, all A
instances are completely equivalent and indistinguishable.当我们谈论类型检查时,所有A
实例都是完全等价且不可区分的。 They have the same set of methods and attributes (including types).它们具有相同的一组方法和属性(包括类型)。 We can ask: "which type errors can be introduced or removed, if we explicitly declare object to be self
instance and not just self
type?"我们可以问:“如果我们明确声明 object 是self
实例而不仅仅是self
类型,那么可以引入或移除哪些类型错误?” I really cannot think of any.我真的想不出任何。 If you want this for semantics, use docstring - types should not be abused for everything.如果你想要这个用于语义,请使用 docstring - 类型不应该被滥用。 self
object is absolutely the same as any other A()
instance for type checker. self
object 与类型检查器的任何其他A()
实例完全相同。
Your first code sample is almost fine.您的第一个代码示例几乎没问题。 Annotate return as A
to tell that it returns instance of class A
, it will work for final class:将 return 注释为A
以告知它返回 class A
实例,它将适用于最终的 class:
class A:
def foo(self) -> A:
return self
However, this approach has a drawback (it is good explained in PEP673 about Self
type):然而,这种方法有一个缺点(在 PEP673 中关于Self
类型有很好的解释):
class AChild(A):
pass
# mypy
reveal_type(AChild().foo()) # N: revealed type is "__main__.A"
If you create new A
in foo
and return it, then this approach is perfect.如果您在foo
中创建新A
并将其返回,那么这种方法是完美的。 If you return self
- it is valid, but not precise.如果您return self
- 它是有效的,但不准确。 That's why we need Self
type.这就是为什么我们需要Self
类型。
Self
type is too modern Self
类型太现代As of now, mypy
does not support Self
type described in PEP673 , so it fails with a cryptic message.截至目前, mypy
不支持PEP673中描述的Self
类型,因此它失败并显示一条神秘消息。 However, your usage in 3rd example was perfectly valid and will work after implementation in type checkers (see 5-th code block in "Motivation" section of PEP).但是,您在第三个示例中的用法是完全有效的,并且在类型检查器中实现后将起作用(请参阅 PEP 的“动机”部分中的第 5 个代码块)。
Here's how you can use Self
(assuming python=3.11
not to bother with typing_extensions
and near future for mypy
support):以下是您如何使用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"
It is great, but does not work now.这很棒,但现在不起作用。 Note that other checkers (namely pyright
and pyre
) have support for this.请注意,其他检查器(即pyright
和pyre
)对此提供支持。
Self
type without using it在不使用的情况下实现Self
类型However, you can mimic Self
accurately with a few lines of code (and python >= 3.7
, AFAIR).但是,您可以使用几行代码(和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"
Now this works.现在这有效。 All subclasses will return their class instance.所有子类都将返回它们的 class 实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.