[英]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.