'How to update history dictionary attribute of a class instance and preserve order?
I am new to class programming. I am trying to save initial attributes (which are a dictionary) of my object in its history, and then update history with the changes of attributes. Below the code:
import datetime
import pytz
class Property:
""" Simple property class """
@staticmethod
def _current_time():
utc_time = datetime.datetime.utcnow()
return pytz.utc.localize(utc_time)
def __init__(self, link, attributes):
self._link = link
self.__attributes = attributes
self._history = [(Property._current_time(), attributes)]
def update(self, new_attributes):
def dictdiff(d1, d2):
return dict(set(d2.items()) - set(d1.items()))
attr_change = dictdiff(self.__attributes, new_attributes)
self.__attributes.update(attr_change)
self._history.append((Property._current_time(), attr_change))
def show_attributes(self):
return self.__attributes
def show_history(self):
# how to show changes in time?
return self._history
prop = Property(1234, {"Price":3000, "Active":"Yes"})
prop.update({"Price":2500, "Active":"Yes"})
prop.update({"Active":"No"})
prop.show_history()
And output:
Out[132]:
[(datetime.datetime(2018, 10, 28, 10, 24, 19, 712385, tzinfo=<UTC>),
{'Price': 2500, 'Active': 'No'}),
(datetime.datetime(2018, 10, 28, 10, 24, 19, 712385, tzinfo=<UTC>),
{'Price': 2500}),
(datetime.datetime(2018, 10, 28, 10, 24, 19, 712385, tzinfo=<UTC>),
{'Active': 'No'})]
First item in history should actually be:
(datetime.datetime(2018, 10, 28, 10, 24, 19, 712385, tzinfo=<UTC>),
{"Price":3000, "Active":"Yes"})
I tried this but without success. It seems that init function is updating history of initialization as attributes are updated, and in the meanwhile in the history at the first place I want to see attributes that were first-time initialized.
Solution 1:[1]
The problem is that you're modifying the dictionary in the history with this code:
self.__attributes.update(attr_change)
You're basically doing this:
>>> attributes = {}
>>> history = [attributes]
>>> attributes.update(foo=3)
>>> history
[{'foo': 3}]
This is easily fixed by storing a copy of the dictionary in the history:
self._history = [(Property._current_time(), attributes.copy())]
Solution 2:[2]
You want the first history entry be a copy of the attributes
.
self._history = [(Property._current_time(), dict(attributes))]
As your code is now, the first history entry references the current attribute dictionary.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Aran-Fey |
Solution 2 | Antti Haapala -- Слава Україні |