More pythonic way to change an element of a tuple?

Manuel M. Garcia mgarcia at cole-switches.com
Wed Nov 27 19:29:40 EST 2002


On Wed, 27 Nov 2002 09:58:44 -0800, in comp.lang.python you wrote:
(edit)
>I frequently have to change a single element of a tuple, and I wind up 
>doing something like this:

Not recommended to have something that is mutable to give a hash
value. The internal implementation of the dictionary gets confused if
a key changes.

class list_with_hash(list):
    def __hash__(self):
        return hash(tuple(self))

dict0 = {}
dict1 = {}
for i in range(10):
    dict0[list_with_hash([i])] = i
    dict1[list_with_hash([i])] = 9-i

for k in dict1.keys():
    k[0] = 9 - k[0]

print 'dict0 = %r' % (dict0)
print 'dict1 = %r' % (dict1)

for k in dict0.keys():
    try:
        v = dict0[k]
    except KeyError:
        print 'could not find key %r in dict0' % (k)
    else:
        print 'dict0[%r] = %r' % (k,v)

for k in dict1.keys():
    try:
        v = dict1[k]
    except KeyError:
        print 'could not find key %r in dict1' % (k)
    else:
        print 'dict1[%r] = %r' % (k,v)

The dictionaries 'dict0' and 'dict1' print out the same, but most of
they keys in 'dict1' just cannot be found at all.

If you change the 'list_with_hash' class to give the same hash for all
elements like this:

class list_with_hash(list):
    def __hash__(self):
        return 0

you will no longer have the problem of the dictionary not able to find
its own keys.  But now the performance of the dictionary will be
lousy:

import time

class list_with_hash0(list):
    def __hash__(self):
        return hash(tuple(self))
    
class list_with_hash1(list):
    def __hash__(self):
        return 0

t1 = time.clock()
dict0 = {}
for i in range(5000):
    dict0[list_with_hash0([i])] = i
for i in range(5000):
    x = dict0[list_with_hash0([i])]
t2 = time.clock()
print 'time for list_with_hash0: %.3f' % (t2-t1)

t1 = time.clock()
dict1 = {}
for i in range(5000):
    dict1[list_with_hash1([i])] = i
for i in range(5000):
    x = dict1[list_with_hash1([i])]
t2 = time.clock()
print 'time for list_with_hash1: %.3f' % (t2-t1)

Manuel



More information about the Python-list mailing list