[英]Can Python type hints handle a generic class changing its own type in a method?
我有一個現有的 class 可以在某個方法調用時更改重要類型。 它看起來像這樣:
class RememberLast:
def __init__(self, last):
self._last = last
def set(self, new_last):
self._last = new_last
def get(self):
return self._last
remember = RememberLast(5)
type(remember.get()) # int
remember.set('wow')
type(remember.get()) # str
remember.set(4.5)
type(remember.get()) # float
理想情況下, remember
的類型將從RememberLast[int]
更改為RememberLast[str]
然后更改為RememberLast[float]
。 有沒有辦法用類型提示來表示這種情況?
在set()
中以不同的類型提示返回self
並不理想,因為存在調用者。 對於這些不使用返回值的現有調用者,類型將保持為RememberLast[int]
即使類型已“銷毀”並且不再正確。
我指的現有 class 是twisted.internet.defer.Deferred
,它允許鏈接回調。 最后一個返回值的類型成為下一個回調的參數。 因此,可以將Deferred
的類型視為添加到它的最后一個回調的類型。
我將假設RememberLast
必須能夠處理除int
s、 string
s 和float
s 之外的東西(或超過有限的類型聯合),因為否則你可以只使用Union[int, str, float]
。
不幸的是,我對您可以使用比Any
更具體的注釋感到悲觀,原因有兩個:
Any
用於動態類型代碼。 如果可以使用更具體的東西,他們會這么說的。Any
”。您可以使用通用 class 來跟蹤變化的類型。
定義兩個 generics。
from typing import TypeVar, Generic, Type
T = TypeVar("T")
R = TypeVar("R")
class RememberLast(Generic[T]):
def __init__(self, last: T):
self._last = last
def set(self, new_last: R) -> "RememberLast[R]":
return RememberLast(new_last)
def get(self) -> T:
return self._last
請注意,為了使其工作,您需要重新分配set
back to remember
的結果。 我們需要這樣做,因為set
的結果包含新的類型提示信息。
# int
remember = RememberLast(5) # RememberLast[int]
print(type(remember.get())) # <class 'int'>
# str
remember = remember.set("abc") # RememberLast[str]
print(type(remember.get())) # <class 'str'>
# float
remember = remember.set(4.5) # RememberLast[float]
print(type(remember.get())) # <class 'float'>
不幸的是,python 中的類型提示不會阻止類型更改,例如,如果您使用下面的類型提示,它將給出相同的 output:
class RememberLast:
def __init__(self, last: int):
self._last = last
def set(self, new_last: int):
self._last = new_last
def get(self):
return self._last
remember = RememberLast(5)
type(remember.get()) # int
remember.set('wow')
type(remember.get()) # str
remember.set(4.5)
type(remember.get()) # float
有兩種方法可以強制方法僅采用特定類型:
isinstance
斷言:class RememberLast:
def __init__(self, last: int):
assert isinstance(last, int)
self._last = last
def set(self, new_last: int):
assert isinstance(last, int)
self._last = new_last
def get(self):
assert isinstance(last, int)
return self._last
remember = RememberLast(5)
type(remember.get()) # int
remember.set('wow')
type(remember.get()) # raises AssertionError
remember.set(4.5)
type(remember.get()) # raises AssertionError
mypy my_python_script.py
這應該是 output
my_python_script.py:26: error: Argument 1 to "set" of "RememberLast" has incompatible type "str"; expected "int"
my_python_script.py:28: error: Argument 1 to "set" of "RememberLast" has incompatible type "float"; expected "int"
Found 2 errors in 1 file (checked 1 source file)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.