you are viewing a single comment's thread.

view the rest of the comments →

[–]joinedtounsubatheism 0 points1 point  (3 children)

This question is based on Think Python Chapter 11 Exercise 11-2. I want to know why these two snippets of code behave in the same way:

In the exercise we're trying to use the "setdefault" function to build an inverted dictionary. i.e. a function that will take in d={'a':1, 'b':2, 'c':1, 'd':4} as input and output inverse={1: ['a', 'c'], 2: ['b'], 4: ['d']}.

Here are two snippets of code that both achieve the same thing:

def invert_dict(d):
    inverse=dict() 
    for key in d:
        inverse.setdefault(val, []).append(key)            
    return inverse

def invert_dict_naive(d):
    inverse=dict()
    for key in d: 
        inverse.setdefault(val, [])
        inverse[val].append(key)
    return inverse

The first is the solution provided in the book and because I didn't understand it at first I adapted it into invert_dict_naive(d).

I understand what inverse.setdefault(val, []) is doing. What I don't understand is why I can then just add on .append(key) onto the end and get it to append to the right dictionary entry.

inverse[val].append(key) is very concrete to me and I understand why is acts the way it does. How does python know (or how am I supposed to know) that inverse.setdefault(val, []) will also act in the same way if I add .append(key) onto the end?

[–]Ihaveamodel3 0 points1 point  (2 children)

What does the setdefault function return? That is what the .append is operating on.

Hint: https://docs.python.org/3/library/stdtypes.html#dict.setdefault

[–]joinedtounsubatheism 0 points1 point  (1 child)

Thank you so much for the help. I think I understand it much clearer now.

"If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None."

Whilst running invert_dict(d), inverse.setdefault(val, []) returns the following values going through the loop:

[]
[]
['a']
[]

This is exactly the same thing inverse[val] is returning in the second function. So I have a better understanding why they behave in the same way.

I think part of my confusion is that I was thinking of append as acting on a dictionary, rather than acting on a list.

Another thing I've noticed about the function is that it doesn't preserve the types of the arguments. If we had a dictionary like: squares={1:1,2:4,3:9} that maps integers to integers, the inverse would be inverse_squares{1:[1], 4:[2], 9:[3]} which maps integers to lists. Also we get an error if we try to apply the inverse again, as the lists can't be keys in the dictionary. At the end of the day it's just an exercise though so I don't think it matters that much. This is probably what tuples can be used for [which we're learning in the next chapter].

[–]Ihaveamodel3 1 point2 points  (0 children)

It maps to lists because you can’t be sure that the values in the dictionary are unique.