wotanii
wotanii

Reputation: 2836

How can I get a modified copy of a immutable object?

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

Answers (2)

hynek
hynek

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

Sam
Sam

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

Related Questions