我如何注释 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 self
是 Entry
的实例。当我在 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_function
,c_function
将不会显示,反之亦然。当我不在 Something
和 AnotherThing
class 的 return 类型上键入提示时,vscode 正确地假设 Entry
是 return 类型,然后我可以在调用 a_function
时获得 c_function
的智能感知
解决方案是使用 TypeVar
将 Something
和 AnotherThing
函数的 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。
借口:此代码无用,用例也可能无用,但我只是想弄清楚如何让它工作,以便存根文件显示正确的签名。这个问题看起来很混乱,所以我会尽力解释,但我非常愿意接受改进问题结构的建议。
环境: 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 self
是 Entry
的实例。当我在 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_function
,c_function
将不会显示,反之亦然。当我不在 Something
和 AnotherThing
class 的 return 类型上键入提示时,vscode 正确地假设 Entry
是 return 类型,然后我可以在调用 a_function
c_function
的智能感知
解决方案是使用 TypeVar
将 Something
和 AnotherThing
函数的 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。