如何将datetime.now().isoformat()添加到NamedTuple的__init__中?

3
当然,我已经尝试过:
class PdfContentRecord(NamedTuple):
    filename: str
    page: int
    cache: dict
    data: dict = dict()
    accessed: str = None

    def __new__(cls, *args, **kwargs):
        self = super().__new__(*args, **kwargs)
        self.accessed = datetime.now().isoformat()
        return self

我遇到了与如何为命名元组的子类提供额外初始化相同的错误。

我无法确定attrs是否能帮助我(太难理解了)。dataclasses.dataclass可能能够帮助,但它仅支持Python 3.7。

或者我可以编写自己的类,可能还要使用__slots__...

编辑:

您是否阅读了您链接的问题中的答案?

使用from collection import namedtuple可以工作,但是from typing import NamedTuple不能。


2
你还在实例之间共享相同的默认数据字典,可能是一个错误。 - undefined
@wim 没问题,谢谢。但是在 Python 3.6 之后的版本中很难进行回溯移植。 - undefined
你在链接的问题中读到了答案吗? - undefined
1
@wim 感谢你,我找到了__attrs_post_init__ - undefined
@user2357112 __new__同样存在问题。 - undefined
@pylang 我使用 record._asdict() 将其发送到数据库。 - undefined
2个回答

3
如果您正在使用dataclasses,则可以直接使用字段的default_factory。 如果您正在使用attrs,则同样可以提供一个factory可调用对象。
如果您正在使用typing.NamedTuple,则应该能够通过额外的类型层来实现此操作:
from datetime import datetime
from typing import NamedTuple


class _PdfContentRecord(NamedTuple):
    filename: str
    page: int
    cache: dict
    data: dict = None
    accessed: str = None


class PdfContentRecord(_PdfContentRecord):

    def __new__(cls, filename, page, cache, data=None, accessed=None):
        if data is None:
            data = {}
        if accessed is None:
            accessed = datetime.now().isoformat()
        return super().__new__(cls, filename, page, cache, data, accessed)

可以说,使用NamedTuple的一些优点会丧失,可能直接编写子类型更好。


你能解释一下这里的__new__重写吗?看起来你可以在类创建时设置类属性,对吗? - undefined
不是设置它们,而是拦截参数。当子类化不可变类型(如元组、日期时间等)时,通常会覆盖__new__而不是__init__ - undefined

2

非常优美的答案,需要执行pip install attrs(这启发了dataclass)。

import attr

@attr.s
class PdfFileRecord:
    name: str = attr.ib()
    type: str = attr.ib()
    cache: dict = attr.ib()
    data: dict = attr.ib(factory=dict)
    accessed: str = attr.ib(factory=lambda: datetime.now().isoformat())

对于 dataclass 版本,需要 Python 3.7+ 或者 Python 3.6 的后移版本

import dataclasses

@dataclasses.dataclass
class PdfFileRecord:
    name: str
    type: str
    cache: dict
    data: dict = dataclasses.field(default_factory=dict)
    accessed: str = dataclases.field(default_factory=lambda: datetime.now().isoformat())

我正在使用Python 3.7,但我计划分享我的代码。 - undefined
2
注意:现在你已经根据@wim的建议修复了代码,你可能已经注意到根本不需要__attrs_post_init__。你可以简单地将accessed定义为accessed: str = attr.ib(init=False, factory=lambda: datetime.now().isoformat()),这样就完全不需要__attrs_post_init__了(而且你也避免了将默认值信息与属性本身的信息分开)。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接