【问题标题】:How can I annotate a method that returns self so that the stub file shows correct return types?如何注释返回 self 的方法,以便存根文件显示正确的返回类型?
【发布时间】:2021-04-13 16:47:38
【问题描述】:

借口:这段代码没用,用例也可能没用,但我只是想弄清楚如何使它工作,以便存根文件显示正确的签名。这个问题似乎令人困惑,因此我正在尽力解释,但我非常愿意接受建议以使问题结构更好。

环境: 蟒蛇:3.7.9 我的 Vscode + Pylance

目录结构:

 .
├──  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函数)中没有指定返回类型时,类型提示是正确的。

但是当我指定返回类型为Entry时,返回类型显示为Any

something.py 带有带注释的返回类型:

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 的返回类型时,python 不知道 Entry 是什么,可以在下一个屏幕截图中看到。所以它将Any类型分配给它:

问题:

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

编辑:

考虑第一个答案,绑定子类并不能完全解决问题,因为智能感知和类型将仅显示调用的方法方法。例如,如果我调用a_functionc_function 将不会显示,反之亦然。当我没有在 SomethingAnotherThing 类的返回类型上键入提示,并且 vscode 正确假定 Entry 是返回类型时,我可以在调用 c_function 时获得智能感知 a_function

【问题讨论】:

    标签: python mypy python-typing


    【解决方案1】:

    解决方案是使用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找到。

    【讨论】:

    • 谢谢!我会接受这个作为答案,但有一个小问题。当我将STAT 分别绑定到SomethingAnotherThing 时,类型提示和智能感知将显示相应类的方法。例如,如果我打电话给a_functionc_function 将不再出现。这就是我想要克服的。我将更新 OP 以包含屏幕截图。
    • 我需要做的是从 init 绑定 Entry 类,以复制来自 vscode 的默认无类型行为。
    • 我没有得到相同的结果。当我将此答案中的上述代码复制并粘贴到something.py 中时,1.py 中的代码为每个后续函数调用显示了正确的智能感知(Entry 的返回类型)。但是,如果我不在 SomethingAnotherThing 函数中分别使用 self: STself: AT 注释 self 参数,我确实会从您的编辑中看到相同的结果。也许这在您的测试中被遗漏了?
    • 你是对的。我确实忘记注释 self 本身。
    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 2023-02-14
    • 2014-01-26
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多