dictionary mutability, hashability, __eq__, __hash__
Veek M
vek.m1234 at gmail.com
Sun Nov 27 10:39:12 EST 2016
Veek M wrote:
> Jussi Piitulainen wrote:
>
>> Veek M writes:
>>
>> [snip]
>>
>>> Also if one can do x.a = 10 or 20 or whatever, and the class
>>> instance is mutable, then why do books keep stating that keys need
>>> to be
>>> immutable? After all, __hash__ is the guy doing all the work and
>>> maintaining consistency for us. One could do:
>>>
>>> class Fruit:
>>> editable_value = ''
>>> def __hash__(self):
>>> if 'apple' in self.value:
>>> return 10
>>> elif 'banana' in self.value:
>>> return 20
>>>
>>>
>>> and use 'apple' 'bannana' as keys for whatever mutable data..
>>> Are the books wrong?
>>
>> The hash does not do all the work, and the underlying implementation
>> of a dictionary does not react appropriately to a key changing its
>> hash value. You could experiment further to see for yourself.
>>
>> Here's a demonstration that Python's dictionary retains both keys
>> after they are mutated so that they become equal, yet finds neither
>> key (because they are not physically where their new hash value
>> indicates).
>>
>> I edited your class so that its methods manipulate an attribute that
>> it actually has, all hash values are integers, constructor takes an
>> initial value, objects are equal if their values are equal, and the
>> written representation of an object shows the value (I forgot
>> quotes).
>>
>> test = { Fruit('apple') : 'one', Fruit('orange') : 'two' }
>>
>> print(test)
>> print(test[Fruit('orange')])
>> # prints:
>> # {Fruit(apple): 'one', Fruit(orange): 'two'}
>> # two
>>
>> for key in test: key.value = 'banana'
>>
>> print(test)
>> print(test[Fruit('banana')])
>>
>> # prints:
>> # {Fruit(banana): 'one', Fruit(banana): 'two'}
>> # Traceback (most recent call last):
>> # File "hash.py", line 25, in <module>
>> # print(test[Fruit('banana')])
>> # KeyError: Fruit(banana)
>
> ah! not so: that's because you are messing/changing the integer value
> for the key. If apple-object was returning 10, you can't then return
> 20 (the text mangling seems to be completely irrelevant except you
> need it to figure out which integer to return but barring that..).
>
> Here's an example of what you're doing (note 'fly' is returning 20 BUT
> the object-instance is 'apple' - that obviously won't work and has
> nothing to do with my Q, err.. (don't mean to be rude):
> class Fruit(object):
> def __init__(self, text):
> self.text = text
>
> def mangle(self,text):
> self.text = text
>
> def __hash__(self):
> if 'apple' in self.text:
> return 10
> elif 'orange' in self.text:
> return 20
> elif 'fly' in self.text:
> return 20
> else:
> pass
>
> apple = Fruit('apple')
> orange = Fruit('orange')
>
> d = { apple : 'APPLE_VALUE', orange : 'ORANGE_VALUE' }
> print d
>
> apple.mangle('fly')
> print d[apple]
>
> The Question is specific.. what I'm saying is that you can change
> attributes and the contents and totally mash the object up, so long as
> __hash__ returns the same integer for the same object. Correct?
>
> Where does __eq__ fit in all this?
How does MUTABILITY play a role in this?? __hash__ *HAS* to return an
integer which is immutable anyhow.. And as far as UDT's are concerned
they don't need to be immutable, they just need to return their integer-
key correctly..
More information about the Python-list
mailing list