python dict setdefault, confused

后端 未结 3 990
一生所求
一生所求 2020-12-19 03:09

I was looking for an algorithm, and I can\'t figure out why the dict d has values in it and curr does not. I think it does not seem like anything i

相关标签:
3条回答
  • d = dict() --> initializes an empty dictionary and binds it to the name d; so you have a dictionary object ({}) referenced by name d

    Inside the outer for loop
    curr = d --> binds another name curr to the same object. So, names (d and curr refer to the same object)

    Inside the inner for loop
    During the first iteration letter = 'f'

    curr = curr.setdefault(letter, {})
    

    There are 2 things that are happening in the above statement,

    A) curr.setdefault(letter, {}) --> As per documentation:

    "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.".

    Since, the letter 'f' is not in the initial dictionary object it mutates the initial object to {'f':{}} and returns the value {}, which is not the initial dictionary object, but a new one that was created because of the setdefault statement. At this time both curr and d refer to the initial dictionary object which has since mutated to {'f':{}}.

    B) Reassignment of the name curr to the return value mentioned above. Now, the names curr and d refer to different objects. d refers to the object {'f':{}}, while curr refers to an empty dictionary object, which is actually the value of d['f']. This is why the nesting happens in the original dictionary object, as we go through the loop.

    0 讨论(0)
  • 2020-12-19 03:27

    setdefault(key[, default)

    From the docs:

    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.

    Usage examples

    >>> d = {'a': 1, 'b': 2, 'c': 3}
    >>> d.setdefault('a') # returns the corresponding value for key 'a'
    1
    >>> d.setdefault('a', 10) # returns the corresponding value for key 'a'
    1
    >>> d.setdefault('b') # returns the corresponding value for key 'b'
    2
    >>> d.setdefault('c', 100) # returns the corresponding value for key 'c'
    3
    >>> type(d.setdefault('z')) # because 'z' is not a key of d, None is returned which is the default value of default 
    <class 'NoneType'>
    >>> d.setdefault('z', 666) # returns 666 since key 'z' is not in d
    666
    

    In your code

    I think you are confused because curr = curr.setdefault(letter, {}) always creates a new and empty dict, which is then assigned to curr. This means that instead of overwriting the values, you are adding a nesting level to the original dict for every element in words.

    I also think that what you want to achieve with your code is to create a dictionary with every element in words as key with {} as value, so you can achieve it using the following code that uses a dict-comprehension:

    def what(*words):
        return {word: {} for word in set(words)}
    

    Note: I have added the explanation of setdefault since your questions has been viewed particularly for this case, but I wanted to cover your specific question too.

    0 讨论(0)
  • 2020-12-19 03:29

    Read the documentation for dict.setdefault: it is like get but if the key wasn't present then it is also set:

    >>> my_dict = {}
    >>> my_dict.setdefault('some key', 'a value')
    'a value'
    >>> my_dict
    {'some key': 'a value'}
    >>> my_dict.get('some key2', 'a value2')
    'a value2'
    >>> my_dict
    {'some key': 'a value'}
    

    Modifying a little your example:

    >>> def what(*words):
    ...     d = dict()
    ...     for word in words:
    ...             curr = d
    ...             for letter in word:
    ...                     curr = curr.setdefault(letter, {})
    ...             curr = curr.setdefault('.', '.')
    ...             print 'curr is now: %r while d is %r' % (curr, d)
    ... 
    >>> what('foo')
    curr is now: '.' while d is {'f': {'o': {'o': {'.': '.'}}}}
    

    As you can see curr changes, because when calling setdefault it sometimes(in your example always) create a new dict and set it as value to curr, while d always refers to the original dict. As you can see it is modified after the loop, since it's value is {'f': {'o': {'o': {'.': '.'}}}} which is quite different from {}.

    Probably your confusion is due to the fact that curr = curr.setdefault(letter, {}) always create a new and empty dict, which is then assigned to curr(and thus for every letter you add a nesting level to the original dict instead of overwriting the values).

    See this:

    >>> my_dict = {}
    >>> curr = my_dict
    >>> for letter in 'foo':
    ...     print 'my_dict is now %r. curr is now %r' % (my_dict, curr)
    ...     curr = curr.setdefault(letter, {})
    ... 
    my_dict is now {}. curr is now {}
    my_dict is now {'f': {}}. curr is now {}
    my_dict is now {'f': {'o': {}}}. curr is now {}
    >>> my_dict
    {'f': {'o': {'o': {}}}}
    

    As you can see for every level the my_dict has a new nesting level.

    Maybe, but I'm just guessing, you wanted to obtain something like 'foo' -> {'f': {}, 'o': {}}, in which case you should do:

    >>> my_dict = {}
    >>> for letter in 'foo':
    ...     my_dict.setdefault(letter, {})
    ... 
    >>> my_dict
    {'o': {}, 'f': {}}
    
    0 讨论(0)
提交回复
热议问题