Suppose I have a dataclass with a set method. How do I extend the repr method so that it also updates whenever the set method is called:
from dataclasses import dataclass
@dataclass
class State:A: int = 1B: int = 2def set(self, var, val):setattr(self, var, val)
Ex:
In [2]: x = State()In [3]: x
Out[3]: State(A=1, B=2)In [4]: x.set("C", 3)In [5]: x
Out[5]: State(A=1, B=2)In [6]: x.C
Out[6]: 3
The outcome I would like
In [7]: x
Out[7]: State(A=1, B=2, C=3)
The dataclass
decorator lets you quickly and easily build classes that have specific fields that are predetermined when you define the class. The way you're intending to use your class, however, doesn't match up very well with what dataclasses are good for. You want to be able to dynamically add new fields after the class already exists, and have them work with various methods (like __init__
, __repr__
and presumably __eq__
). That removes almost all of the benefits of using dataclass
. You should instead just write your own class that does what you want it to do.
Here's a quick and dirty version:
class State:_defaults = {"A": 1, "B": 2}def __init__(self, **kwargs):self.__dict__.update(self._defaults)self.__dict__.update(kwargs)def __eq__(self, other):return self.__dict__ == other.__dict__ # you might want to add some type checking heredef __repr__(self):kws = [f"{key}={value!r}" for key, value in self.__dict__.items()]return "{}({})".format(type(self).__name__, ", ".join(kws))
This is pretty similar to what you get from types.SimpleNamespace
, so you might just be able to use that instead (it doesn't do default values though).
You could add your set
method to this framework, though it seems to me like needless duplication of the builtin setattr
function you're already using to implement it. If the caller needs to dynamically set an attribute, they can call setattr
themselves. If the attribute name is constant, they can use normal attribute assignment syntax instead s.foo = "bar"
.