attrs icon indicating copy to clipboard operation
attrs copied to clipboard

evolve() and attr.ib(init=False, default="foo")

Open hynek opened this issue 6 years ago • 1 comments

As pointed out in https://github.com/ericvsmith/dataclasses/issues/42#issuecomment-330198369 attr.evolve() behaves rather weird if an attribute has

  1. init=False,
  2. a default/__attrs_post_init__, and
  3. attribute(s) are modified on the instance.

The new resulting object will always have the default value.

I think I can live with that limitation if we document it and it's probably a good reason to resolve #207 with sticking assoc around with a better name?


Giving it further thought, the raison d'être for evolve are immutable objects…so I think it's fine to just document this edge case and leave it be?

hynek avatar Sep 25 '17 18:09 hynek

import attr

@attr.s class MyDataClass: init_value: int = attr.ib(init=False) default_value: int = attr.ib(default=0)

def __attrs_post_init__(self):
    self.init_value = 42  # Modifying an attribute in __attrs_post_init__

def evolve_example(): original_instance = MyDataClass() evolved_instance = attr.evolve(original_instance, init_value=100)

return evolved_instance

Documentation for the edge case

print(""" As pointed out in ericvsmith/dataclasses#42 (comment), attr.evolve() behaves in a specific way when an attribute has:

  1. init=False,
  2. a default/attrs_post_init, and
  3. attribute(s) are modified on the instance.

The new resulting object will always have the default value for that attribute. This behavior is because evolve is primarily designed for immutable objects.

Given the nature of evolve and its purpose for immutable objects, it is acceptable to document this edge case and leave it as is. """)

Example usage of attr.evolve()

evolved_obj = evolve_example() print(f"Evolved object: {evolved_obj}")

ljluestc avatar Sep 20 '23 22:09 ljluestc