Определение следующего подкласса:
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
должны существовать только во время инициализации, но из некоторых исследований я вижу, что они помещаются в __dataclass_fields__
, и поэтому replace
пытается их использовать.
Я использую Python 3.6, поэтому мой пакет dataclasses
является бэкпортом, а не встроенным пакетом для Python 3.7+.
Я нашел эту строку в документации по классам данных:
Переменные только для инициализации без значений по умолчанию, если они существуют, должны быть указаны при вызове replace(), чтобы их можно было передать в init() и post_init(). .
что означает, что если бы у меня было исходное значение instance.foo
, я теоретически мог бы сделать:
replace(instance, bar="baz", foo="value of foo")
Но у меня нет исходного значения instance.foo
.
Как избежать этой ошибки, если я хочу создать копию существующего экземпляра класса данных?
__post_init__
может запускать произвольный код с вашей InitVar, и нет никакого способа угадать это, учитывая другие атрибуты вашего класса данных. InitVar даже не нужно влиять на состояние вашего класса данных, возможно, он просто вызывает побочный эффект, например, создает файл с его именем. Как бы вы воспроизвели это поведение, не зная его ценности? Концептуально невозможно скопировать-сконструировать или заменить экземпляр класса данных без явной передачи всех InitVars. - person Arne   schedule 02.03.2021