Suppose that you have a python class MyObject such that instances contain a list of data and that the MyObject class as a __getitem__ method defined as follows:
def __getitem__(self, index):
return self.data[index]
Suppose that we wish to modify the above __getitem__ method to something like
def __getitem__(self, index):
return self.data[my_function(index)]
where my_function is some function that transforms an alternative indexing system (say tuples of integers into the list index system - non-negative integers). Here my_function might be self.map or OtherClass.map or something else that makes the above code valid python code. We want to enable the user to change this function - including using the identity function (i.e. no conversion). This can be done easily enough.
But here is what I want to do. Suppose that I have a bunch of instances $p_1,p_2,..,p_k$ of 'MyObject' class using some map map_1 and I have another bunch of instances $q_1,q_2,...,q_t$ using some map map_2.
I want to change the map that the instances $p_1,p_2,..,p_k$ use from
map_1tomap_2. I do not want to do this by looping over each instance $p_1,p_2,..,p_k$ and setting the index map tomap_2but rather only doing $O(1)$ work (i.e. not $O(k)$ work).Then I want to have all $p_1,p_2,..,p_k,q_1,q_2,...,q_t$ instances using
map_2.Then I want to change these instances to use a new map
map_3where it again only takes the same amount of constant time to change.
I can see how to do this is C/C++ using references but not in python. The user provides the map functions and there can be many. The best I can get is as follows:
# A simple Map class to hold maps
class MapDict:
def __init__(self):
self.loaded_maps = dict()
def make_map(self, fid):
def index_funct(index):
return self.loaded_maps[fid](index)
return index_funct
# A simple class for data
class MyObject:
def __init__(self,data):
self.data = data
self._map = self._identity_map
def _identity_map(self, index):
return index
def set_map(self, input_map):
self._map = input_map
def __getitem__(self, index):
return self.data[self._map(index)]
# Create some MyObjects with sample data
p1=MyObject(range(1000))
p2=MyObject(range(1000))
q1=MyObject(range(1000))
q2=MyObject(range(1000))
#Create a class to hold the maps
map_dict = MapDict()
# Define a few map functions to use in indexing
def map1(index):
return index[0]+index[1]
def map2(index):
return index[0]*index[1]
def map3(index):
return index[0]+10*index[1]
# Load the maps into the map dict class
map_dict.loaded_maps[1] = map1
map_dict.loaded_maps[2] = map2
# Set the maps for the MyObjects
p1.set_map(map_dict.make_map(1))
p2.set_map(map_dict.make_map(1))
q1.set_map(map_dict.make_map(2))
q2.set_map(map_dict.make_map(2))
# Now change maps for p1, p2
map_dict.loaded_maps[1] = map2
# Now change maps for p1 p2 q1 q2
map_dict.loaded_maps[1] = map3
map_dict.loaded_maps[2] = map3
The problem with this approach is that I now have two instances of map3 in a dictionary rather than a single location. So if I want to change map3 to map4 for all instances using map3 then I have so change two locations. A guess that I could provide another list/dictionary on top of this to keep track but this seems overkill. Also I want to make sure that _getitem__ remains very fast (relative to the map function chosen) as I expect it to be used a lot.
I expect that there are a much better way to do this so ideas are welcome.