Phil Saulnier
Phil Saulnier

Reputation: 13

Unsure why dictionary is mutating

Doing a self-study of Python via MIT Open Courseware, and ran into a problem with this bit of code below. When I run this function either alone or within another function, it mutates the originally passed value 'hand', and I am not sure why. I set two local variables (hand0 and tester) to hand, the first to preserve the initial value, and the second to iterate over. However, all three change, while I'm only expecting 'tester' to do so. Other than mutating 'hand', the function works as expected.

(Values as passed to the function vary within set parameters: word_list is a list of valid English words, word is a string that I replace within this function for testing, and hand is a dictionary of letters and their associated counts. Debugging code commented out.)

def is_valid_word(word, hand, word_list):
    """
    Returns True if word is in the word_list and is entirely
    composed of letters in the hand. Otherwise, returns False.
    Does not mutate hand or word_list.

    word: string
    hand: dictionary (string -> int)
    word_list: list of lowercase strings
    """
    hand0 = hand
    tester = hand
    #display_hand(hand)
    #display_hand(tester)
    word = raw_input('test word: ')
    length = len(word)
    disc = True
    for c in range(length):
        if word[c] in tester.keys() and tester[word[c]]>0:
            #print tester[word[c]]
            #display_hand(hand)
            #display_hand(tester)
            tester[word[c]]=tester[word[c]]-1            
        else:
            #print 'nope'
            disc = False
    if word not in word_list:
        disc = False
    #print disc
    #display_hand(hand)
    #display_hand(tester)
    #display_hand(hand0)
    return disc

Upvotes: 1

Views: 1438

Answers (2)

Mark Ransom
Mark Ransom

Reputation: 308168

When you do tester = hand you're not making a copy of hand, you're making a new reference to the same object. Any modifications you make to tester will be reflected in hand.

Use tester = hand.copy() to fix this: http://docs.python.org/2/library/stdtypes.html#dict.copy

Upvotes: 5

mgilson
mgilson

Reputation: 309919

When you do tester = hand, you're only creating a new reference to the hand object. In other words, tester and hand are the same object. You could see this if you checked their id:

print id(tester)
print id(hand)  #should be the same as `id(tester)`

Or equivalently, compare with the is operator:

print tester is hand  #should return `True`

To make a copy of a dictionary, there is a .copy method available:

tester = hand.copy()

Upvotes: 10

Related Questions