Why dict.get(key) instead of dict[key]?

后端 未结 10 2504
生来不讨喜
生来不讨喜 2020-11-21 05:51

Today, I came across the dict method get which, given a key in the dictionary, returns the associated value.

For what purpose is this funct

相关标签:
10条回答
  • 2020-11-21 06:10

    For what purpose is this function useful?

    One particular usage is counting with a dictionary. Let's assume you want to count the number of occurrences of each element in a given list. The common way to do so is to make a dictionary where keys are elements and values are the number of occurrences.

    fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
    d = {}
    for fruit in fruits:
        if fruit not in d:
            d[fruit] = 0
        d[fruit] += 1
    

    Using the .get() method, you can make this code more compact and clear:

    for fruit in fruits:
        d[fruit] = d.get(fruit, 0) + 1
    
    0 讨论(0)
  • 2020-11-21 06:11

    I will give a practical example in scraping web data using python, a lot of the times you will get keys with no values, in those cases you will get errors if you use dictionary['key'], whereas dictionary.get('key', 'return_otherwise') has no problems.

    Similarly, I would use ''.join(list) as opposed to list[0] if you try to capture a single value from a list.

    hope it helps.

    [Edit] Here is a practical example:

    Say, you are calling an API, which returns a JOSN file you need to parse. The first JSON looks like following:

    {"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}
    

    The second JOSN is like this:

    {"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}
    

    Note that the second JSON is missing the "submitdate_ts" key, which is pretty normal in any data structure.

    So when you try to access the value of that key in a loop, can you call it with the following:

    for item in API_call:
        submitdate_ts = item["bids"]["submitdate_ts"]
    

    You could, but it will give you a traceback error for the second JSON line, because the key simply doesn't exist.

    The appropriate way of coding this, could be the following:

    for item in API_call:
        submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")
    

    {'x': None} is there to avoid the second level getting an error. Of course you can build in more fault tolerance into the code if you are doing scraping. Like first specifying a if condition

    0 讨论(0)
  • 2020-11-21 06:12

    get takes a second optional value. If the specified key does not exist in your dictionary, then this value will be returned.

    dictionary = {"Name": "Harry", "Age": 17}
    dictionary.get('Year', 'No available data')
    >> 'No available data'
    

    If you do not give the second parameter, None will be returned.

    If you use indexing as in dictionary['Year'], nonexistent keys will raise KeyError.

    0 讨论(0)
  • 2020-11-21 06:18

    Why dict.get(key) instead of dict[key]?

    0. Summary

    Comparing to dict[key], dict.get provides a fallback value when looking up for a key.

    1. Definition

    get(key[, default]) 4. Built-in Types — Python 3.6.4rc1 documentation

    Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

    d = {"Name": "Harry", "Age": 17}
    In [4]: d['gender']
    KeyError: 'gender'
    In [5]: d.get('gender', 'Not specified, please add it')
    Out[5]: 'Not specified, please add it'
    

    2. Problem it solves.

    If without default value, you have to write cumbersome codes to handle such an exception.

    def get_harry_info(key):
        try:
            return "{}".format(d[key])
        except KeyError:
            return 'Not specified, please add it'
    In [9]: get_harry_info('Name')
    Out[9]: 'Harry'
    In [10]: get_harry_info('Gender')
    Out[10]: 'Not specified, please add it'
    

    As a convenient solution, dict.get introduces an optional default value avoiding above unwiedly codes.

    3. Conclusion

    dict.get has an additional default value option to deal with exception if key is absent from the dictionary

    0 讨论(0)
  • 2020-11-21 06:19

    What is the dict.get() method?

    As already mentioned the get method contains an additional parameter which indicates the missing value. From the documentation

    get(key[, default])
    

    Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

    An example can be

    >>> d = {1:2,2:3}
    >>> d[1]
    2
    >>> d.get(1)
    2
    >>> d.get(3)
    >>> repr(d.get(3))
    'None'
    >>> d.get(3,1)
    1
    

    Are there speed improvements anywhere?

    As mentioned here,

    It seems that all three approaches now exhibit similar performance (within about 10% of each other), more or less independent of the properties of the list of words.

    Earlier get was considerably slower, However now the speed is almost comparable along with the additional advantage of returning the default value. But to clear all our queries, we can test on a fairly large list (Note that the test includes looking up all the valid keys only)

    def getway(d):
        for i in range(100):
            s = d.get(i)
    
    def lookup(d):
        for i in range(100):
            s = d[i]
    

    Now timing these two functions using timeit

    >>> import timeit
    >>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
    20.2124660015
    >>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
    16.16223979
    

    As we can see the lookup is faster than the get as there is no function lookup. This can be seen through dis

    >>> def lookup(d,val):
    ...     return d[val]
    ... 
    >>> def getway(d,val):
    ...     return d.get(val)
    ... 
    >>> dis.dis(getway)
      2           0 LOAD_FAST                0 (d)
                  3 LOAD_ATTR                0 (get)
                  6 LOAD_FAST                1 (val)
                  9 CALL_FUNCTION            1
                 12 RETURN_VALUE        
    >>> dis.dis(lookup)
      2           0 LOAD_FAST                0 (d)
                  3 LOAD_FAST                1 (val)
                  6 BINARY_SUBSCR       
                  7 RETURN_VALUE  
    

    Where will it be useful?

    It will be useful whenever you want to provide a default value whenever you are looking up a dictionary. This reduces

     if key in dic:
          val = dic[key]
     else:
          val = def_val
    

    To a single line, val = dic.get(key,def_val)

    Where will it be NOT useful?

    Whenever you want to return a KeyError stating that the particular key is not available. Returning a default value also carries the risk that a particular default value may be a key too!

    Is it possible to have get like feature in dict['key']?

    Yes! We need to implement the __missing__ in a dict subclass.

    A sample program can be

    class MyDict(dict):
        def __missing__(self, key):
            return None
    

    A small demonstration can be

    >>> my_d = MyDict({1:2,2:3})
    >>> my_d[1]
    2
    >>> my_d[3]
    >>> repr(my_d[3])
    'None'
    
    0 讨论(0)
  • 2020-11-21 06:20

    A gotcha to be aware of when using .get():

    If the dictionary contains the key used in the call to .get() and its value is None, the .get() method will return None even if a default value is supplied.

    For example, the following returns None, not 'alt_value' as may be expected:

    d = {'key': None}
    assert None is d.get('key', 'alt_value')
    

    .get()'s second value is only returned if the key supplied is NOT in the dictionary, not if the return value of that call is None.

    0 讨论(0)
提交回复
热议问题