dict ключи должны быть хэшируемыми, что означает, что они имеют неизменное значение хэш .dict значения могут быть или не быть изменяемыми;однако, если они изменчивы, это повлияет на ваш второй вопрос.
"Изменения в ключах" не будут отражены между двумя диктовками.Изменения неизменяемых значений, таких как строки, также не будут отражены.Изменения в изменяемых объектах, таких как определяемые пользователем классы, будут отражены, поскольку объект хранится по идентификатору (то есть по ссылке).
class T(object):
def __init__(self, v):
self.v = v
t1 = T(5)
d1 = {'a': t1}
d2 = d1.copy()
d2['a'].v = 7
d1['a'].v # = 7
d2['a'] = T(2)
d2['a'].v # = 2
d1['a'].v # = 7
import copy
d3 = copy.deepcopy(d2) # perform a "deep copy"
d3['a'].v = 12
d3['a'].v # = 12
d2['a'].v # = 2
Я думаю, что это объясняется первыми двумя ответами.
Не знаю, что я знаю об этом.
некоторые дополнительные мысли :
Для понимания поведения ключей необходимо знать две основные вещи: ключи должны быть hashable (что означает, что они реализуют object.__hash__(self)
), и они также должны быть«сопоставимый» (что означает, что они реализуют что-то вроде object.__cmp__(self)
).Один важный вывод из документов: по умолчанию хеш-функции пользовательских объектов возвращают id()
.
Рассмотрим этот пример:
class K(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return self.x + self.y
k1 = K(1, 2)
d1 = {k1: 3}
d1[k1] # outputs 3
k1.x = 5
d1[k1] # KeyError! The key's hash has changed!
k2 = K(2, 1)
d1[k2] # KeyError! The key's hash is right, but the keys aren't equal.
k1.x = 1
d1[k1] # outputs 3
class NewK(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return self.x + self.y
def __cmp__(self, other):
return self.x - other.x
nk1 = NewK(3, 4)
nd1 = {nk1: 5}
nd1[nk1] # outputs 5
nk2 = NewK(3, 7)
nk1 == nk2 # True!
nd1[nk2] # KeyError! The keys' hashes differ.
hash(nk1) == hash(nk2) # False
nk2.y = 4
nd1[nk2] # outputs 5
# Where this can cause issues:
nd1.keys()[0].x = 5
nd1[nk1] # KeyError! nk1 is no longer in the dict!
id(nd1.keys()[0]) == id(nk1) # Yikes. True?!
nd1.keys()[0].x = 3
nd1[nk1] # outputs 5
id(nd1.keys()[0]) == id(nk1) # True!
Значения гораздо проще понять, в dict хранятся ссылки на объекты.Читайте разделы на хэш.Такие вещи, как строки, являются неизменяемыми, если вы «измените» их, то указание, в котором вы их изменили, теперь ссылается на новый объект.Объекты, которые являются изменяемыми, могут быть «изменены на месте», поэтому значение обоих диктов будет меняться.
d1 = {1: 'a'}
d2 = d1.copy()
id(d1[1]) == id(d2[1]) # True
d2[1] = 'z'
id(d1[1]) == id(d2[1]) # False
# the examples in section 2 above have more examples of this.
В любом случае, вот основные пункты всего этого:
- Для ключей это может быть не изменчивость , а скорее стойкость и сопоставимость , о которых вы заботитесь.
- Вы заботитесь о изменчивости длязначения, потому что по определению значение изменяемого объекта может быть изменено без изменения ссылки на него.
Я не думаю, что существует общий способ проверки любой из этих точек.Тесты на пригодность будут зависеть от вашего варианта использования.Например, может быть достаточно проверить, что объект выполняет или не реализует __hash__
и функции сравнения (__eq__
или __cmp__
).Аналогично, вы можете каким-то образом «проверить» метод __setattr__
объекта, чтобы определить, является ли он изменяемым.