I would like to create a data structure containing several settings, these settings will be used to calculate register values of a hardware device. To avoid reconfiguring all settings of the hardware device, I would like to have each variable inside of the data structure remember if it has been changed or not. Then later I would call upon all variables to see which ones are changed to then only write to the connected registers.
I can create a class that remembers if any change has occurred to it's internally stored value, I am however experiencing difficulties with returning and resetting the has_changed variable. This due to the overloading of the __get__ function prohibiting the usage of other functions inside of the class.
In the simplified example I have made a class called Table (which should contain variables such as: height, width, length, ...) The current implementation has the class TrackedValidatedInteger which checks if the change is valid.
I would like the variable property has_changed to be obtainable and resettable from inside of the class Table.
class TrackedValidatedInteger():
def __init__(self, min_value=None, max_value=None):
self.min_value = min_value
self.max_value = max_value
self.has_changed = False
self.value = None
def __get__(self, obj, objecttype=None):
return self.value
def __set__(self, obj, value):
if self.validate_set(value):
self.value = value
self.has_changed = True
return 1
return 0
def get_has_changed(self):
return self.has_changed
def reset_has_changed(self):
self.has_changed = False
def validate_set(self, value):
if self.min_value:
if self.min_value > value:
print("Value should be between " + str(self.min_value) + " and " + str(self.max_value))
return 0
if self.max_value:
if self.max_value < value:
print("Value should be between " + str(self.min_value) + " and " + str(self.max_value))
return 0
return 1
class Table():
length = TrackedValidatedInteger(min_value=0, max_value=3)
height = TrackedValidatedInteger(min_value=0, max_value=6)
width = TrackedValidatedInteger(min_value=0, max_value=7)
def __init__(self, length=0, height=0, width=0):
self.length = length
self.height = height
self.width = width
def reset_has_changed_1(self):
self.length.has_changed = False
self.height.has_changed = False
self.width.has_changed = False
def reset_has_changed_2(self):
self.length.reset_has_changed()
self.height.reset_has_changed()
self.width.reset_has_changed()
p = Table()
p.length = 3 # will set the variable
p.length = 9 # will not set the variable
# p.length.get_has_changed() # This does not work as the p.length will call __get__ resulting in an integer which does not have get_has_changed()
# p.reset_has_changed_1() # This does not work for the same reason
# p.reset_has_changed_2() # This does not work for the same reason
The problem I find is that the __get__ function gets automatically called whenever I try to access any other part of the TrackedValidatedInteger class. Can I access the other variables and functions in any other way? If there are any suggestions on how achieve the same result in another way, I would be glad to hear it. I would personally like to keep the simple setting of the variables (p.length = 3), if not possible this can be changed.
Any help would be greatly appreciated.
I like the idea of doing this from a descriptor. You can take advantage of the fact that a descriptor can know the name of the attribute to which it is bound via the
__set_name__method, and use that to maintain attributes on the target object:Given the above implementation, we can create a class
Examplelike this:And then observe the following behavior:
Instead of maintaining a per-attribute
<name>_changedvariable, you could instead maintain asetof changed attributes:In that case, we get:
This is nice because you can iterate over
e._changed_attributesif you need to record all your changed values.