This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Allow dataclasses to be updated in place
Type: enhancement Stage: resolved
Components: Versions: Python 3.8
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: eric.smith, remi.lapeyre, rhettinger, theophile
Priority: normal Keywords:

Created on 2019-01-17 14:23 by theophile, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (7)
msg333872 - (view) Author: Théophile Chevalier (theophile) * Date: 2019-01-17 14:23
Calling dataclasses.replace(instance, **changes) returns a new object of the same type.

From my understanding there is, however, no method to update in place fields of a dataclass from another one.

I propose to add dataclasses.update(instance_to_update, other_instance, **changes).

This would for instance allow one to change all fields of current object in a sturdy way.
In my case, I currently call obj.__dict__.update(other_obj.__dict__) to perform the operation, but I know it has always to be done pretty carefully.

If this is accepted, I'm willing to post the change.
msg333906 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-01-17 22:47
What would the interaction be between other_instance and changes? Why is this API different from .replace()?
msg333909 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-01-17 23:19
I'm don't see the point of this proposal.  The fields of dataclasses are already mutable, so they can be updated just like any other object (no need for a special mechanism):

a = InventoryItem(name='Widget', unit_price=37.25, quantity_on_hand=10)

a.quantity_on_hand -= 1           # Sold one
a.unit_price *= 0.90              # Ten percent off sale

Also, it's not hard to directly take data from one instance to another:

a.name = master_catalog.name
a.unit_price = master_catalog.unit_price
msg333910 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-01-17 23:29
I agree that I don't see the point, unless there's something I'm missing with other_instance. Or maybe the proposal is for it to also work with frozen dataclasses? I'm definitely -1 on that.

So unless there's something I'm missing where normal attribute assignment wouldn't work, I'm leaning toward rejecting this. What is it about dataclasses that would need this feature, where regular classes don't? Just do what you'd do with regular classes.
msg333962 - (view) Author: Théophile Chevalier (theophile) * Date: 2019-01-18 13:55
I understand your points, I'll give an example with a simplified version of my problem:


import dataclasses
import othermodule # is an external dependency

@dataclass
class City:
    name: str
    position: othermodule.Point # Point is a dataclass

    def update_position(self):
        obj = anymodule.get_position(name=self.name)
        
        # The classic solution would be to do
        self.position.x = obj.x
        self.position.y = obj.y

        # what if othermodule adds z (altitude) to Point?
        # we could imagine:
        dataclasses.update(self.position, obj)

        # I'm currently doing:
        self.position.__dict__.update(obj.__dict__)

Maybe I simply handle the issue the wrong way, so my dataclass proposal is out of scope.
msg333967 - (view) Author: Théophile Chevalier (theophile) * Date: 2019-01-18 14:14
I cannot do self.position = obj because I have references on position elsewhere.
msg344369 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-06-03 02:19
I'm going to reject this. There's nothing special about dataclasses that would require a feature like this.
History
Date User Action Args
2022-04-11 14:59:10adminsetgithub: 79942
2019-06-03 02:19:20eric.smithsetstatus: open -> closed
resolution: rejected
messages: + msg344369

stage: resolved
2019-01-18 14:14:31theophilesetmessages: + msg333967
2019-01-18 13:55:27theophilesetmessages: + msg333962
2019-01-17 23:29:31eric.smithsetmessages: + msg333910
2019-01-17 23:19:32rhettingersetnosy: + rhettinger
messages: + msg333909
2019-01-17 22:47:58eric.smithsetassignee: eric.smith

messages: + msg333906
nosy: + eric.smith
2019-01-17 14:24:02remi.lapeyresetnosy: + remi.lapeyre
2019-01-17 14:23:09theophilecreate