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

spa*_*tar 13 python python-3.x python-dataclasses

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

Run Code Online (Sandbox Code Playgroud)

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

Arn*_*rne 15

您遇到的潜在问题似乎与此处描述的问题相同。该帖子的简短版本是,在函数签名(包括数据类生成的__init__方法)中,强制参数(如 NamedEvent 的name)不能跟在具有默认值的参数(这是定义 Event 的行为所必需的updated_at)之后 - 子字段将始终跟随其父级。

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

我上面链接的帖子讨论了一些您可以应用来解决问题的模式,但作为更好的选择,您还可以使用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
Run Code Online (Sandbox Code Playgroud)

通过验证器的默认值规范有点麻烦,但总的来说它是一个非常有用的包,它修复了使用数据类时遇到的许多缺点,以及更多。

使用类定义,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')
Run Code Online (Sandbox Code Playgroud)