假设我有一个实现方法链的类:
from __future__ import annotations
class M:
def set_width(self, width: int)->M:
self.width = width
return self
def set_height(self, height: int)->M:
self.height = height
return self
字符串
我可以这样使用它:
box = M().set_width(5).set_height(10)
型
这是可行的,但如果我有一个子类M3D:
class M3D(M):
def set_depth(self, depth: int) -> M3D:
self.depth = depth
return self
型
现在我不能这样做:
cube = M3D().set_width(2).set_height(3).set_depth(5)
型
我在mypy中得到以下错误:
_test_typeanotations.py:21: error: "M" has no attribute "set_depth"; maybe "set_width"
型
因为set_width()
返回一个没有方法set_depth
的M
。我已经看到建议为每个子类重写set_width()
和set_height()
以指定正确的类型,但这将是为每个方法编写的大量代码。必须有一个更简单的方法。
这也与特殊方法有关,例如__enter__
传统上返回self
,所以如果有一种方法来指定它,而不需要在子类中提到它,那就太好了。
3条答案
按热度按时间kb5ga3dv1#
从Python 3.11开始,你可以这样做:
字符串
bihw5rsg2#
经过大量的研究和分析,我找到了一种在mypy中有效的方法,尽管Pycham有时仍然会猜错类型。
技巧是让
self
成为var类型:字符串
最后一行在mypy中运行良好,但pycharm有时仍然会自动完成
set_depth
,即使在M3D
上调用时,.copy()
实际上返回M
。wribegjk3#
这在任何使用继承的语言中都是一个经典问题。不同的语言对此有不同的处理方式:
set_depth
之前强制转换set_height
的结果Python是一种动态类型语言,所以没有强制转换指令。所以你有三种可能的方法:
以下仅是我的意见。
如果可能的话,我会避免使用“不要打扰”的方式,因为如果你在代码中留下警告,那么如果有新的警告,你将不得不在每次更改后进行控制。
我不会仅仅为了摆脱警告而重写方法。毕竟Python是一种动态类型语言,甚至允许鸭子类型。如果我知道代码是正确的,我会避免添加无用的代码(DRY和KISS原则)
因此,我将假设注解挂起注解控件是有原因的,并使用它们(我称之为 * 不要在这里打扰我 *)。