今天,我遇到了根据子方法的实现来输入父方法的任务。我的意思是,我有一堂这样的课:
from abc import ABC, abstractmethod
class PageIterator(ABC):
def __init__(self, last_page):
self.current_page = 1
self.last_page = last_page
def __iter__(self):
return self
def __next__(self):
if self.current_page > self.last_page:
raise StopIteration
response = self.get()
self.current_page += 1
return response
@abstractmethod
def get(self):
...
我认为从上下文中可以清楚地看出,该类是通过网站页面的顺序通道的实现。在这种情况下,有一个抽象方法get,其实现落在子类上。根据实现的不同,get它可以返回不同的对象。例如,实现如下:
from dataclasses import dataclass
@dataclass()
class CurrentPage:
page: int
@dataclass()
class LastPage:
last_page: int
class MainPage(PageIterator):
def get(self):
return CurrentPage(self.current_page)
class CommentPage(PageIterator):
def get(self):
return LastPage(self.current_page)
用法大致如下:
for i in MainPage(100):
print(i)
for j in CommentPage(100):
print(j)
代码可以工作,但问题是IDE(我尝试了PyCharm和 的几个版本VSCode)中的静态代码分析工具无法独立确定迭代器和显示返回值的类型Any。合乎逻辑的做法是添加如下内容:
@abstractmethod
def get(self) -> Union[CurrentPage, LastPage]:
...
或这个:
def __next__(self) -> Union[CurrentPage, LastPage]:
会出现提示,但返回类型是IDE混合的(如果对象很大并且具有许多内部字段,则至关重要)。我想为每个实现提供单独的提示。此时,我的技术已经不够了,我唯一能想到的就是将其__next__也抽象化,并在每个子类中将其与类型提示一起编写,但这已经看起来像是重复的代码,这不太好。 。
泛型文档。确实,Python 文档中的一切并不总是显而易见的。但
generics除了方括号之外,它们与其他语言并没有特别不同[...]。甚至自动完成建议也可以工作:
python_3.13添加了默认类型参数,[T:MyType = DefaultType]但到目前为止,这个 alpha 版本几乎不受任何地方支持。以前使用的是 Stupid
T = TypeVar('T'),但这已经过时了,因为几乎每个人都已经切换/正在切换到python_3.12.