Python 方法重写 - 派生类中的参数比基类更具体

问题描述 投票:0回答:1

假设我想创建一个名为

Document
的抽象基类,并且希望其所有子类实现名为
from_paragraphs
的类方法,该方法从一系列
Paragraph
对象构造文档。但是,
LegalDocument
只能从
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

然而,Pyright 对此有所抱怨,因为派生类上的

from_paragraphs
违反了里氏替换原则。如何表达我想要的?

python python-3.x inheritance methods overriding
1个回答
0
投票

这种模式称为工厂模式:根据输入,您会得到不同类型的对象。你那里的东西不起作用,因为:

# Because Document should not have knowledge of derived class:
doc = Document.from_paragraphs(...)

# Because type mismatch
doc = LegalDocument.from_paragraphs([AcademicParagraphs()]) 

这是我解决这个问题的方法:

class Document:
    def __init__(self, paragraphs):
        self.paragraphs = paragraphs

class LegalDocument(Document):
    pass

class AcademicDocument(Document):
    pass

class Paragraph:
    def __init__(self, text):
        self.text = text

class LegalParagraph(Paragraph):
    pass

class AcademicParagraph(Paragraph):
    pass

def create_document(*paragraphs):
    # assume that all paragraphs are of the same type
    if isinstance(paragraphs[0], LegalParagraph):
        klass = LegalDocument
    elif isinstance(paragraphs[0], AcademicParagraph):
        klass = AcademicDocument
    else:
        raise TypeError()

    return klass(paragraphs)


d1 = create_document(LegalParagraph("foo"), LegalParagraph("bar"))
assert isinstance(d1, LegalDocument)

d2 = create_document(AcademicParagraph("moo"))
assert isinstance(d2, AcademicDocument)

注释

  • 我将有一套简单的课程,而不是搞乱ABC
  • 没有类方法,
    __ini__()
    就足够了
  • 我有一个工厂函数
    create_document
    ,它将创建一个文档,其中类型取决于输入
  • 另一种方法是调整
    Document.__new__()
    方法,但这需要一些关于
    __new__()
    工作原理的知识,但并不是每个人都知道这一点。
© www.soinside.com 2019 - 2024. All rights reserved.