Python - 类中的静态方法创建该类的实例

qal*_*lis 6 python json static-methods dictionary python-typing

我有从 JSON 创建的 Python 数据类(实际上有很多)。我想要一种从 JSON 创建类实例的方法。

我有这样的事情:

class FromJSONMixin:
    @staticmethod
    @abstractmethod
    def from_json(json: Union[Dict, TypedDict], **kwargs):
        raise NotImplementedError


class PatientJSON(TypedDict):
    ID: str
    Name: str
    Description: str
    BirthDate: str


@dataclass
class Patient(FromJSONMixin):
    name: str
    birth_date: str
    description: str

    @staticmethod
    def from_json(json: PatientJSON, **kwargs) -> Patient:
        return Patient(
        name=json["Name"],
        birth_date=json["BirthDate"],
        description=raw_data["Description"])
Run Code Online (Sandbox Code Playgroud)

我想Patient从中创建对象PatientJSON(结构与现有数据库相关,我必须与它集成;它还进行一些名称属性翻译,如上所示)。我创建了FromJSONMixin来显式标记可以从 JSON 的相关类创建的类(例如PatientJSON)。

问题:-> Patient:我收到零件错误Unresolved reference 'Patient'。为什么?我无法在同一类的方法中键入类对象?我是否必须放弃输入返回类型?

Ama*_*anK 9

这是创建具有良好类型注释的模块时的常见问题。问题是当 python 解释器解析创建 Patient 类的代码时。方法的返回类型注释引用了正在解析且尚未创建的Patient.from_json类Patient 。为了解决这个问题,您通常将类名用引号括在返回注释中,使其成为字符串。但现在 MyPy 和其他类型检查器存在问题。他们不允许字符串返回注释,所以这里是一个很好的解决方案:

class MyClass(SomeOtherClass):
    def __init__(self, param_a):
        self.attr_a = param_a
    
    def foo(self, bar: MyClass) -> MyClass:
        return MyClass(self.attr_a + 1)
Run Code Online (Sandbox Code Playgroud)

这将引发未解决的参考错误。

要解决此问题,您可以用引号将方法返回注释括起来

class MyClass(SomeOtherClass):
    def __init__(self, param_a):
        self.attr_a = param_a
    
    def foo(self, bar: 'MyClass') -> 'MyClass':
        return MyClass(self.attr_a + bar.attr_a)
Run Code Online (Sandbox Code Playgroud)

这将有助于提高可读性,但不适用于 MyPy 等类型检查器。因此,对于像 MyPy 这样的检查器,您可以创建一个 TypeVar。

from typing import TypeVar, Type

MyClassT = TypeVar('MyClassT', bound='MyClass')

class MyClass(SomeOtherClass):
    def __init__(self, param_a):
        self.attr_a = param_a
    
    def foo(self, bar: Type[MyClassT]) -> MyClassT:
        return MyClass(self.attr_a + bar.attr_a)
Run Code Online (Sandbox Code Playgroud)

2023 年更新

随着python 3.11版本中type的引入Self,上面的例子可以写成:

from typing import Self

class MyClass(SomeOtherClass):
    def __init__(self, param_a):
        self.attr_a = param_a

    def foo(self, bar: Self) -> Self:
        return MyClass(self.attr_a + bar.attr_a)
Run Code Online (Sandbox Code Playgroud)