mal*_*sen 5 python methods inheritance overriding python-3.x
假设我想创建一个名为 的抽象基类Document。我希望类型检查器保证其所有子类都实现一个名为 的类方法from_paragraphs,该方法从一系列Paragraph对象构造一个文档。然而, aLegalDocument只能从LegalParagraph对象构造,而AcademicDocument- 只能从AcademicParagraph对象构造。
我的直觉是这样做:
from abc import ABC, abstractmethod
from typing import Sequence
class Document(ABC):
@classmethod
@abstractmethod
def from_paragraphs(cls, paragraphs: Sequence["Paragraph"]):
pass
class LegalDocument(Document):
@classmethod
def from_paragraphs(cls, paragraphs: Sequence["LegalParagraph"]):
return # some logic here...
class AcademicDocument(Document):
@classmethod
def from_paragraphs(cls, paragraphs: Sequence["AcademicParagraph"]):
return # some logic here...
class Paragraph:
text: str
class LegalParagraph(Paragraph):
pass
class AcademicParagraph(Paragraph):
pass
Run Code Online (Sandbox Code Playgroud)
然而,Pyright 对此有所抱怨,因为from_paragraphs在派生类上违反了里氏替换原则。如何确保每个派生类都实现某种from_paragraphs类型?Paragraph
事实证明,这可以使用泛型来解决:
from abc import ABC, abstractmethod
from typing import Generic, Sequence, TypeVar
ParagraphType = TypeVar("ParagraphType", bound="Paragraph")
class Document(ABC, Generic[ParagraphType]):
@classmethod
@abstractmethod
def from_paragraphs(cls, paragraphs: Sequence[ParagraphType]):
pass
class LegalDocument(Document["LegalParagraph"]):
@classmethod
def from_paragraphs(cls, paragraphs):
return # some logic here...
class AcademicDocument(Document["AcademicParagraph"]):
@classmethod
def from_paragraphs(cls, paragraphs):
return # some logic here...
class Paragraph:
text: str
class LegalParagraph(Paragraph):
pass
class AcademicParagraph(Paragraph):
pass
Run Code Online (Sandbox Code Playgroud)
说bound="Paragraph"保证 ParagraphType 代表 (的子类) Paragraph,但派生类不应实现from_paragraphs所有段落类型,而仅实现它们选择的一种。类型检查器还会自动找出 的参数类型,paragraphs为LegalDocument.from_paragraphs我节省了一些工作:)