Search code examples
pythondictionarymutated

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

Solution

  • 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()