#python #reference #data-access
Вопрос:
Предположим, что у вас есть класс python MyObject
, экземпляры которого содержат список данных и что MyObject
класс как __getitem__
метод определен следующим образом:
def __getitem__(self, index):
return self.data[index]
Предположим, что мы хотим изменить приведенный выше __getitem__
метод на что-то вроде
def __getitem__(self, index):
return self.data[my_function(index)]
где my_function
находится некоторая функция, которая преобразует альтернативную систему индексации (скажем, кортежи целых чисел в систему индексов списка — неотрицательные целые числа). Здесь my_function
может быть self.map
или OtherClass.map
или что-то еще, что делает приведенный выше код допустимым кодом python. Мы хотим разрешить пользователю изменять эту функцию, в том числе с помощью функции идентификации (т. Е. Без преобразования). Это можно сделать достаточно легко.
Но вот что я хочу сделать. Предположим,что у меня есть куча экземпляров $p_1, p_2,.., p_k$ класса MyObject, использующего некоторую карту map_1
,и у меня есть еще одна куча экземпляров $q_1, q_2,…, q_t$, использующих некоторую карту map_2
.
- Я хочу изменить карту,которую используют экземпляры $p_1, p_2,.., p_k$, с
map_1
наmap_2
. Я не хочу делать это,зацикливаясь на каждом экземпляре $p_1, p_2,.., p_k$ и устанавливая отображение индекса наmap_2
, а только выполняя $O(1)$ работу (т. Е. Не $O(k)$ работу). - Затем я хочу,чтобы все экземпляры $p_1, p_2,.., p_k,q_1,q_2,…,q_t$ использовали
map_2
. - Затем я хочу изменить эти экземпляры, чтобы использовать новую карту
map_3
, где для изменения снова требуется столько же постоянного времени.
Я вижу, как это сделать на C/C , используя ссылки, но не на python. Пользователь предоставляет функции карты, и их может быть много. Лучшее, что я могу получить, это следующее:
# 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
Проблема с этим подходом заключается в том, что теперь у меня есть два экземпляра map3
в словаре, а не в одном месте. Поэтому, если я хочу перейти map3
на map4
использование для всех экземпляров map3
, я должен изменить два местоположения. Предположение, что я мог бы предоставить еще один список/словарь в дополнение к этому, чтобы отслеживать, но это кажется излишним. Кроме того, я хочу убедиться, что _getitem__
это остается очень быстрым (относительно выбранной функции карты), так как я ожидаю, что она будет часто использоваться.
Я ожидаю, что есть гораздо лучший способ сделать это, так что идеи приветствуются.
Ответ №1:
Если я правильно понимаю, вы хотели бы иметь возможность переключать метод-getitem для группы экземпляров. Я думаю, что наличие отдельного класса для хранения функций сопоставления кажется излишним, когда ваш класс MyObject может хранить его для групп своих экземпляров и отправлять функцию.
class MappedList:
mappers = {}
def __init__(self, data, group, mapper=None):
self.data = data
self.group = group
# add mapping function to dict if creating new group
if self.group not in type(self).mappers.keys():
type(self).mappers[self.group] = mapper
def __getitem__(self, item):
return self.data[type(self).mappers[self.group](item)]
@classmethod
def edit_group_mapper(cls, group, mapper):
# reset groups getter function
cls.mappers[group] = mapper
Функции для переназначения индекса в данные:
def map1(item):
return item 1
def map2(item):
# should catch if remapped item not in data here
return item 2
Создание нескольких групп с помощью этого:
p1 = MappedList(['a', 'b', 'c'], group=1, mapper=map1)
p2 = MappedList(['d', 'e', 'f'], group=1)
m1 = MappedList(['g', 'h', 'i'], group=2, mapper=map2)
m2 = MappedList(['j', 'k', 'l'], group=2)
Тестирование первой функции сопоставления и тестирование измененной функции сопоставления:
print(p1[0], p2[0])
MappedList.edit_group_map(group=1, mapper=map2)
print(p1[0], p2[0])
ВОЗВРАТ:
b e
c f