简体   繁体   English

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

[英]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:我已经尝试过的事情:

  1. annotating it as 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
  2. annotating it as 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不相距甚远。
  3. annotating is as 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.我找不到任何与此密切相关的问题,因此将尝试解释。

What does "same type" mean for type checking “相同类型”对于类型检查意味着什么

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 ?但是只要你想要s1s2是否可以接受? 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()实例完全相同。

Simple solution: return class instance简单的解决方案:返回 class 实例

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.请注意,其他检查器(即pyrightpyre )对此提供支持。

Implementing 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.

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