我如何注释 return 自身的方法,以便存根文件显示正确的 return 类型?

How can I annotate a method that returns self so that the stub file shows correct return types?

借口:此代码无用,用例也可能无用,但我只是想弄清楚如何让它工作,以便存根文件显示正确的签名。这个问题看起来很混乱,所以我会尽力解释,但我非常愿意接受改进问题结构的建议。

环境: Python:3.7.9 Mypy Vscode + 皮兰斯

目录结构:

 .
├──  1.py
└──  testcode
   ├──  __init__.py
   └──  modules
      ├──  __init__.py
      └──  something.py

里面1.py

from testcode import Entry

e = Entry('a').a_function().b_function().c_function()

里面__init__.py

from .modules.something import Something, AnotherThing

class Entry(Something, AnotherThing):
    def __init__(self, a: str):
        self.a = a

在这种情况下,return selfEntry 的实例。当我在 b_function(或 a、b、c 函数)中没有指定 return 类型时,类型提示是正确的。

但是当我将return类型指定为Entry时,return类型显示为Any

something.py 带有 return 类型注释:

class Something(object):
    def a_function(self) -> 'Entry':
        return self

    def b_function(self) -> 'Entry':
        return self

class AnotherThing:
    def c_function(self) -> 'Entry':
        return self

因此,为了尝试克服这个问题,我尝试使用 stubgen 和命令 stubgen -o . -p testcode 创建存根文件,该命令会创建所有 pyi 文件,并且 something.pyi 包括:

class Something:
    def a_function(self) -> Entry: ...
    def b_function(self) -> Entry: ...

class AnotherThing:
    def c_function(self) -> Entry: ...

存根生成后的目录:

 .
├──  1.py
└──  testcode
   ├──  __init__.py
   ├──  __init__.pyi
   └──  modules
      ├──  __init__.py
      ├──  __init__.pyi
      ├──  something.py
      └──  something.pyi

现在我明白了为什么这不起作用,因为当我在 Something 的方法中指定 Entry 的 return 类型时,python 不知道什么 Entry 可以在下一个屏幕截图中看到。所以它将 Any 类型分配给它:

问题:

知道当 Entry 的 return 类型没有在 Something 的方法中注释时,它会选择正确的 return 类型(因此提供了很好的intellisense),我如何正确注释和生成存根文件,以便在注释 return 类型的 self 时它不会 return Any

编辑:

反思第一个答案,绑定子classes 并不能完全解决问题,因为智能感知和类型将只显示被调用的方法。因此,例如,如果我调用 a_functionc_function 将不会显示,反之亦然。当我不在 SomethingAnotherThing class 的 return 类型上键入提示时,vscode 正确地假设 Entry 是 return 类型,然后我可以在调用 a_function

时获得 c_function 的智能感知

解决方案是使用 TypeVarSomethingAnotherThing 函数的 self 参数绑定到那些 类 的子类所以:

from typing import TypeVar


ST = TypeVar('ST', bound='Something')

class Something:
    def a_function(self: ST) -> ST:
        return self

    def b_function(self: ST) -> ST:
        return self

AT = TypeVar('AT', bound='AnotherThing')

class AnotherThing:
    def c_function(self: AT) -> AT:
        return self

可以找到更多信息 here