Изменения в ключе меняют словарь
Есть код, аналогичный данному:
class A:
def __init__(self, i):
self.i = i
def __hash__(self):
return hash(self.i)
def __eq__(self, other):
return self.i == other.i
a = A(1)
m = {a: '1', A(2): '2'}
m[A(1)] # => '1'
a.i = 5
m[A(1)] # KeyError, а хочется '1'
Подскажите, как добиться желаемого поведения? Понятно, что можно использовать что-то такое:
from copy import copy, deepcopy
a = A(1)
m = {copy(a): '1', A(2): '2'}
m[A(1)] # => '1'
a.i = 5
m[A(1)] # '1'
Но выглядит странно и, кажется, должно есть много памяти. Есть ли какое-то стандартное рещение?
Ситуация примерно такая:
m = {i: f(i) for i in some_list}
def get_mutated_value(smt):
return m[m[smth].mutate()]
Ответы (1 шт):
Ну, можно вот так легко добиться требуемого поведения в этом конкретном случае, но не очень понимаю, в чём глубокий смысл.
class A:
def __init__(self, i):
self.i = i
def __hash__(self):
return hash(self.i)
def __eq__(self, other):
return True
a = A(1)
m = {a: '1', A(2): '2'}
m[A(1)] # => '1'
a.i = 5
print(m[A(1)]) # => '1'
print(m[A(2)]) # => '2'
Если что, суть тут в том, что хэш объекта считается только в момент помещения элемента в словарь, а потом проверяется только eq.
Вариант реализации решения, предложенного Xander - с сохранением первоначального состояния, так, думаю, более правильно (при всей кривизне ситуации):
class A:
def __init__(self, i):
self.i = i
self._i = i
def __hash__(self):
return hash(self._i)
def __eq__(self, other):
return self._i == other._i
А, вот вам ещё один смешной вариант, даже не надо менять ваш код класса. Просто используйте в качестве ключа словаря поле класса, а не класс:
a = A(1)
m = {a.i: '1', A(2).i: '2'}
m[A(1).i] # => '1'
a.i = 5
m[A(1).i] # => '1'