[Python] Inheritance with multiple constructors and type annotations

Discussão em 'Python' iniciado por Stack, Maio 31, 2025.

  1. Stack

    Stack Membro Participativo

    I'm trying to create classes that can be saved to a JSON file. The idea is to convert my object to a dataclass that stores only the important attributes. I'll then use something from json or dataclass_wizard to save the dataclass to a file/reconstruct the object later.

    Here's the problem: I want to have an alternate constructor to create the object from the dataclass. I can't overload __init__(), so I'm using a @classmethod. Because the from_briefcase() method is overridden in BiggerBusinessMan, I get a mypy error that this violates the LSP. I can see why I get this error, but is there a way to tell Python that from_briefcase() is meant to be an alternate constructor and not part of the interface? As far as I understand, changing the arguments of __init__() would not violate the LSP, so I want from_briefcase() to be treated similarly.

    from dataclasses import dataclass
    from typing import Self


    @dataclass
    class Briefcase:
    item1: str
    item2: str


    @dataclass
    class BiggerBriefcase(Briefcase):
    item3: str
    # also has `item1` and `item2`


    class BusinessMan:
    def __init__(self):
    self.item1 = ""
    self.item2 = ""

    @classmethod
    def from_briefcase(cls, briefcase: Briefcase) -> Self:
    businessman = cls()
    businessman.item1 = briefcase.item1
    businessman.item2 = briefcase.item2
    return businessman


    class BiggerBusinessMan(BusinessMan):
    def __init__(self):
    super().__init__()
    self.item3 = ""

    @classmethod
    def from_briefcase(cls, briefcase: BiggerBriefcase) -> Self: # mypy error on this line
    # I want to be able to use the base class constructor
    businessman = super().from_briefcase(briefcase)
    businessman.item3 = briefcase.item3
    return businessman


    # these two lines would really be run by some sort of JSON loader to create the dataclasses
    basic_briefcase = Briefcase("notes", "cards")
    bigger_briefcase = BiggerBriefcase("pens", "pencils", "letters")

    # I'm not trying to use `from_briefcase()` polymorphically, it's supposed to be like a constructor
    basic_businessman = BusinessMan.from_briefcase(basic_briefcase)
    bigger_businessman = BiggerBusinessMan.from_briefcase(bigger_briefcase)


    Also, I know I could use a dict instead of a dataclass to solve this issue, but I want stronger typing and to not have to keep track of the correct dictionary keys.

    Worst case I can throw a # type: ignore on there but that seems silly. I could also use __init__(self, briefcase), but I would like to be able to create the object without needing a Briefcase instance.

    Thanks!

    Continue reading...

Compartilhe esta Página