Reputation: 2836
How can I get a modified copy of a immutable object?
I.e. how could some_magical_method
look like in this snipped?
import attr
@attr.s(frozen=True, slots=True)
class Config:
param1: int = attr.ib()
param2: str = attr.ib()
my_base_config = Config(param1=1, param2="2")
my_derived_config = my_base_config.some_magical_method(param2="two")
print(my_derived_config.param1) # output: 1
print(my_derived_config.param2) # output: two
Background: I want to use immutable objects for my configuration. But I also want to avoid code duplication when dealing with very similar configurations, e.g. for unit tests
Upvotes: 0
Views: 476
Reputation: 4146
attrs
has a function specifically for you: https://www.attrs.org/en/stable/api.html#attr.evolve
Since it takes the instance as a first arguments you can use it to define a method too:
@attr.s
class C:
some_magical_method = attr.evolve
Upvotes: 1
Reputation: 1415
Here's a method that does what you want! Add it to your object, here's my code and output:
@attr.s(frozen=True, slots=True)
class Config:
param1: int = attr.ib()
param2: str = attr.ib()
def some_magical_method(self, **kwargs):
params_to_use = {"param1": self.param1, "param2": self.param2}
params_to_use.update(kwargs)
new_obj = Config(**params_to_use)
return new_obj
my_base_config = Config(param1=1, param2="2")
my_derived_config = my_base_config.some_magical_method(param2="two")
>>> print(my_derived_config.param1) # output: 1
1
>>>print(my_derived_config.param2) # output: two
two
The key here is that the method creates the new Config object, using its own values first, and then overwriting with any that are passed into the method using params_to_use.update(kwargs)
. The updated values are then passed to the constructor/init of the new object, which is returned.
Hope that helps, Happy Coding!
Upvotes: 1