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.
1 Answer
Reset to default 3Use 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
typing
module).": PEP 695 is about adding syntactic sugar forGeneric
s et al. It does not deprecatetyping
. – InSync Commented Nov 20, 2024 at 22:46