I have a task connected with reinforcement learning. The state of my environment is described with the class below:
from dataclasses import dataclass
from typing import Tuple
@dataclass
class LearningState:
pre_cross_densities: Tuple[int]
global_aggregated_densities: Tuple[int]
phase_no: int
phase_duration: int
I need the following behaviour (*):
state_1 = LearningState(pre_cross_densities=(0, 4, 5), global_aggregated_densities=(2, 4, 5), phase_no=2, phase_duration=1)
different_state = LearningState(pre_cross_densities=(0, 4, 5), global_aggregated_densities=(2, 4, 8), phase_no=2, phase_duration=1)
state_1_also = LearningState(pre_cross_densities=(0, 4, 5), global_aggregated_densities=(2, 4, 5), phase_no=2, phase_duration=1)
myDic = {state_1: [2], different_state: [7]}
myDic[state_1_also].append(6)
print(myDic[state_1]) # prints [2, 6]
So the dictionary needs to see state_1
and state_1_also
as the same key. Also objects cannot be keys without a __hashable_ method implementation. To overcome these two problems I have created the following decorator.
def hashable(*args):
def wrapper(cls):
setattr(cls, '__hash__', eval('__hash__'))
setattr(cls, '__eq__', eval('__eq__'))
return cls
return wrapper
def __hash__(self):
all_properties = [prop for prop in self.hash_keys if not prop.startswith('__')]
values = tuple([getattr(self, prop) for prop in all_properties])
return hash(values)
def __eq__(self, other):
return self.__hash__() == other.__hash__()
Now I can write my class with the decorator and hash_keys properties as follows:
from dataclasses import dataclass
from typing import Tuple
from services.hashable_decorator import hashable
@hashable()
@dataclass
class LearningState:
pre_cross_densities: Tuple[int]
global_aggregated_densities: Tuple[int]
phase_no: int
phase_duration: int
hash_keys = ['pre_cross_densities', 'global_aggregated_densities', 'phase_no', 'phase_duration']
Code provides a (*) behaviour, but I feel like this is a sculpture. There will be a lot of data and I am also afraid about the performance couse there is a lot of immutable data.
@dataclass(eq=True, Frozen=True)
, then Python makes a hash function for you. If your class is mutable, you shouldn't use it as the key in a dict \$\endgroup\$