无法对具有InitVar的数据类调用replace()

2024-06-16 10:58:52 发布

您现在位置:Python中文网/ 问答频道 /正文

定义以下子类:

from dataclasses import dataclass, replace, field, InitVar

@dataclass
class MyDataClass:
    foo: InitVar[str]
    bar: str
    foo_len: int = field(init=False)
    def __post_init__(self, foo: int):
        self.foo_len = len(foo)

并创建其实例:

instance = MyDataClass(foo="foo", bar="bar")

尝试在实例上调用replace失败:

In[5]: replace(instance, bar="baz")

Traceback (most recent call last):
  File "/home/or/.venv/m/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3343, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-5-5de186c91dc9>", line 1, in <module>
    replace(instance, bar="baz")
  File "/home/or/.venv/m/lib/python3.6/site-packages/dataclasses.py", line 1170, in replace
    changes[f.name] = getattr(obj, f.name)
AttributeError: 'MyDataClass' object has no attribute 'foo'

据我所知,InitVar应该只在init期间存在,但是从一些调查中,我可以看到它们被放入了__dataclass_fields__,因此replace正在尝试使用它们

我使用的是Python3.6,所以我的dataclasses包是后端口,而不是Python3.7+的内置包

我在dataclasses的文档中发现了这一行:

Init-only variables without default values, if any exist, must be specified on the call to replace() so that they can be passed to init() and post_init().

这意味着如果我有instance.foo的原始值,理论上我可以:

replace(instance, bar="baz", foo="value of foo")

但是我没有instance.foo的原始值

如果要创建dataclass现有实例的副本,如何避免此错误


Tags: instanceinselflenfooinitlinebar
1条回答
网友
1楼 · 发布于 2024-06-16 10:58:52

数据类中有InitVar意味着如果不再次显式地传递InitVar,就不能调用构造函数。如果您不再有权访问InitVar,则这将取消replace(instance, ...)MyDataClass(**asdict(instance), ...)的使用资格

如果您所关心的只是获取一个有效的副本,那么您可以使用标准库的copy.copy(或者copy.deepcopy用于有自己容器的数据类,或者嵌套的数据类),它不调用实例的构造函数:

>>> from copy import copy
>>> instance_a = MyDataClass(foo="foo", bar="bar")
>>> instance_b = copy(instance_a)
>>> instance_b
MyDataClass(bar='bar', foo_len=3)
>>> instance_a is instance_b
False

相关问题 更多 >