![](/img/trans.png)
[英]How should one do upper level method that returns self with python pep484 type checking
[英]Python how to type anotate a method that returns self?
假设我有一个实现方法链接的 class:
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
,因此最好有一种方法来指定它而无需在子类中提及它。
这是使用 inheritance 的任何语言中的经典问题。 语言的处理方式不同:
set_height
之前set_depth
的结果Python 是动态类型语言,所以没有强制转换指令。 所以你有3种可能的方式:
以下只是我的看法。
如果可能的话,我会避免不打扰的方式,因为如果您将在代码中留下警告,那么如果有新的警告,您将不得不在每次更改后进行控制。
我不会仅仅为了摆脱警告而重写方法。 毕竟 Python 是一种动态类型语言,甚至允许鸭子类型。 如果我知道代码是正确的,我会避免添加无用的代码(DRY 和 KISS 原则)
因此,我将假设暂停注释控件的注释是出于某种原因而发明的并使用它们(我所说的在这里不会打扰我)。
在 Python 3.11 及其更高版本中,您将能够执行此操作:
from typing import Self
class M:
def set_width(self, width: int) -> Self:
self.width = width
return self
经过大量的研究和实验,我找到了一种在 mypy 中有效的方法,尽管 Pycham 有时仍然会猜错类型。
诀窍是使self
成为类型 var:
from __future__ import annotations
import asyncio
from typing import TypeVar
T = TypeVar('T')
class M:
def set_width(self: T, width: int)->T:
self.width = width
return self
def set_height(self: T, height: int)->T:
self.height = height
return self
def copy(self)->M:
return M().set_width(self.width).set_height(self.height)
class M3D(M):
def set_depth(self: T, depth: int) -> T:
self.depth = depth
return self
box = M().set_width(5).set_height(10) # box has correct type
cube = M3D().set_width(2).set_height(3).set_depth(5) # cube has correct type
attemptToTreatBoxAsCube = M3D().copy().set_depth(4) # Mypy gets angry as expected
最后一行在 mypy 中特别有效,但set_depth
有时仍会自动完成 set_depth ,即使.copy()
实际上返回M
,即使在M3D
上调用也是如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.