Defining the following subclass:
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)
And creating an instance of it:
instance = MyDataClass(foo="foo", bar="bar")
Trying to call replace on the instance fails:
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'
As far as I understand, InitVars should exist during init only, but from some investigation, I can see they are put into __dataclass_fields__ and therefore replace is trying to use them.
I'm using Python 3.6, so my dataclasses package is the backport, not the built-in package for Python 3.7+.
I found this line in dataclasses' documentation:
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().
which means if I had the original value of instance.foo, I could theoretically do:
replace(instance, bar="baz", foo="value of foo")
But I don't have the original value of instance.foo.
How can I avoid this error if I want to create a copy of an existing instance of a dataclass?