admin管理员组

文章数量:1332345

I have a parent class that I made along with a number of child classes that inherit from the parent class. These classes are essentially just python models to read certain documents in from a json or MongoDB and change them from a dictionary into a class. Because of that, I have a standard from_file class method that is only implemented in the parent class. I would like to get the type hinting worked out so that other modules that use these classes know which class will get returned based on the class that called the method.

Parent class:

class ParentDoc(ABC):
    def __init__(self, ver: int = 1) -> None:
        self.ver = ver

    def to_dict(self) -> dict:
        data = self.__dict__.copy()
        data["_class"] = self.__class__.__name__
        return data

    @classmethod
    def from_dict(cls, data: dict) -> ParentDoc:
        return cls(ver=data.get("ver", 1))

    def to_file(self, file_path: str | Path) -> None:
        with open(file_path, "w", encoding="utf8") as json_file:
            json.dump(self.to_dict(), json_file)

    @classmethod
    def from_file(cls, file_path: str | Path) -> ?????:
        with open(file_path, "w", encoding="utf8") as json_file:
            data = create_from_dict(json.load(json_file))
        return data

That helper function in the from_file method is included below.

def create_from_dict(data: dict):
    class_name = data.get("_class")
    if class_name == "ParentDoc":
        return ParentDoc.from_dict(data)
    elif class_name == "ChildDoc":
        return ChildDoc.from_dict(data)
    elif class_name == "Child2Doc":
        return Child2Doc.from_dict(data)
    else:
        raise ValueError(f"Unsupported class: {class_name}")

Then all of the child classes overload the to_dict and from_dict methods but not the to_file and from_file methods.

class ChildDoc(DbDoc):
    def __init__(self, name: str, ver: int = 1) -> None:
        super().__init__(ver=ver)
        self.name = name

    def to_dict(self) -> dict:
        data = super().to_dict()
        data.update({"name": self.name})
        return data

    @classmethod
    def from_dict(cls, data: dict) -> ChildDoc:
        return cls(name=data["name"])

What should I put where all of the question marks are in the parent class so I can call ChildDoc.from_file(json_path) and the type hinting will understand that will return a ChildDoc object and not a ParentDoc object? I currently don't have any type hinting for the output so the linter thinks that it could be any of the parent or child classes, even though I am calling it using one specific child class. And I suppose I could have better type hinting on the create_from_dict function as well.

I would like to use the standard type hinting in Python 3.12 (not have to import the typing module). I have tried Self but that didn't work.

I have a parent class that I made along with a number of child classes that inherit from the parent class. These classes are essentially just python models to read certain documents in from a json or MongoDB and change them from a dictionary into a class. Because of that, I have a standard from_file class method that is only implemented in the parent class. I would like to get the type hinting worked out so that other modules that use these classes know which class will get returned based on the class that called the method.

Parent class:

class ParentDoc(ABC):
    def __init__(self, ver: int = 1) -> None:
        self.ver = ver

    def to_dict(self) -> dict:
        data = self.__dict__.copy()
        data["_class"] = self.__class__.__name__
        return data

    @classmethod
    def from_dict(cls, data: dict) -> ParentDoc:
        return cls(ver=data.get("ver", 1))

    def to_file(self, file_path: str | Path) -> None:
        with open(file_path, "w", encoding="utf8") as json_file:
            json.dump(self.to_dict(), json_file)

    @classmethod
    def from_file(cls, file_path: str | Path) -> ?????:
        with open(file_path, "w", encoding="utf8") as json_file:
            data = create_from_dict(json.load(json_file))
        return data

That helper function in the from_file method is included below.

def create_from_dict(data: dict):
    class_name = data.get("_class")
    if class_name == "ParentDoc":
        return ParentDoc.from_dict(data)
    elif class_name == "ChildDoc":
        return ChildDoc.from_dict(data)
    elif class_name == "Child2Doc":
        return Child2Doc.from_dict(data)
    else:
        raise ValueError(f"Unsupported class: {class_name}")

Then all of the child classes overload the to_dict and from_dict methods but not the to_file and from_file methods.

class ChildDoc(DbDoc):
    def __init__(self, name: str, ver: int = 1) -> None:
        super().__init__(ver=ver)
        self.name = name

    def to_dict(self) -> dict:
        data = super().to_dict()
        data.update({"name": self.name})
        return data

    @classmethod
    def from_dict(cls, data: dict) -> ChildDoc:
        return cls(name=data["name"])

What should I put where all of the question marks are in the parent class so I can call ChildDoc.from_file(json_path) and the type hinting will understand that will return a ChildDoc object and not a ParentDoc object? I currently don't have any type hinting for the output so the linter thinks that it could be any of the parent or child classes, even though I am calling it using one specific child class. And I suppose I could have better type hinting on the create_from_dict function as well.

I would like to use the standard type hinting in Python 3.12 (not have to import the typing module). I have tried Self but that didn't work.

Share Improve this question edited Nov 20, 2024 at 22:51 InSync 10.9k4 gold badges17 silver badges56 bronze badges asked Nov 20, 2024 at 21:19 user2731076user2731076 8131 gold badge7 silver badges26 bronze badges 2
  • "I would like to use the standard type hinting in Python 3.12 (not have to import the typing module).": PEP 695 is about adding syntactic sugar for Generics et al. It does not deprecate typing. – InSync Commented Nov 20, 2024 at 22:46
  • This question is similar to: Type annotation for classmethod returning instance. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. – InSync Commented Nov 20, 2024 at 22:58
Add a comment  | 

1 Answer 1

Reset to default 3

Use typing.Self to indicate that the class method returns an instance of cls.

from typing import Self


class P:
    @classmethod
    def from_file(cls) -> Self:
        return cls()

class C1(P):
    pass

class C2(P):
    pass


reveal_type(P.from_file())  # P
reveal_type(C1.from_file()) # C1
reveal_type(C2.from_file()) # C2

本文标签: