如何在继承的数据类中创建可选字段?

How to create an optional field in a dataclass that is inherited?

from typing import Optional

@dataclass
class Event:
   id: str
   created_at: datetime
   updated_at: Optional[datetime]
   #updated_at: datetime = field(default_factory=datetime.now)  CASE 1
   #updated_at: Optional[datetime] = None                       CASE 2

@dataclass
class NamedEvent(Event):
  name: str

创建事件实例时,我通常不会有 updated_at 字段。我可以将 current time 作为默认值传递,也可以在数据库中插入时为其添加一个值,并在后续使用该对象时获取它。哪种方法更好? 根据我的理解,我无法在不传递 case1 和 case2 中的 updated_at 字段的情况下创建 NamedEvent 实例 ,因为我在 name 字段中没有默认值。

您遇到的根本问题似乎与 中描述的问题相同。 post 的简短版本是在函数签名(包括 dataclass-generated __init__ 方法)中,强制参数(如 NamedEvent 的 name)不能跟在默认参数之后值(定义事件 updated_at 的行为所必需的)- child 的字段将始终跟在其 parent.

的字段之后

因此,要么您的 parent class 中没有默认值(在这种情况下不起作用),要么您的所有 child 字段都需要默认值(这很烦人,有时根本不可行)。

我上面链接的 post 讨论了一些您可以应用来解决您的问题的模式,但作为更好的选择,您也可以使用已经解决了这个问题的第三方包 pydantic为你。示例实现可能如下所示:

import pydantic
from datetime import datetime


class Event(pydantic.BaseModel):
    id: str
    created_at: datetime = None
    updated_at: datetime = None

    @pydantic.validator('created_at', pre=True, always=True)
    def default_created(cls, v):
        return v or datetime.now()

    @pydantic.validator('updated_at', pre=True, always=True)
    def default_modified(cls, v, values):
        return v or values['created_at']


class NamedEvent(Event):
    name: str

通过验证器的 default-value 规范有点麻烦,但总的来说它是一个非常有用的包,它修复了您 运行 在使用数据 classes 时遇到的许多缺点,再加上一些。

使用 class 定义,可以像这样创建 NamedEvent 的实例:

>>> NamedEvent(id='1', name='foo')
NamedEvent(id='1', created_at=datetime.datetime(2020, 5, 2, 18, 50, 12, 902732), updated_at=datetime.datetime(2020, 5, 2, 18, 50, 12, 902732), name='foo')