Python Tricks - Dictionary Tricks(0)

Dictionary Default Values

Python’s dictionaries have a get() method for looking up a key while providing a fallback value. This can be handy in many situations. Let me give you a simple example to show you what I mean. Imagine we have the following data structure that’s mapping user IDs to user names:

name_for_userid = { 
    382: 'Alice',
    950: 'Bob',
    590: 'Dilbert',
}

Now we’d like to use this data structure to write a function greeting() which will return a greeting for a user based on their user ID. Our first implementation might look something like this:

def greeting(userid):
  return 'Hi %s!' % name_for_userid[userid]

It’s a straightforward dictionary lookup. This first implementation technically works—but only if the user ID is a valid key in the name_for_userid dictionary. If we pass an invalid user ID to our greeting function it throws an exception:

>>> greeting(382) 
'Hi Alice!'

>>> greeting(33333333) 
KeyError: 33333333

A KeyError exception isn’t really the result we’d like to see. It would be much nicer if the function returned a generic greeting as a fallback if the user ID can’t be found.
这里是要将错误类型进行改造,以便让用户或者开发者有更好的使用体验

Let’s implement this idea. Our first approach might be to simply do a key in dict membership check and to return a default greeting if the user ID is unknown:

def greeting(userid):
  if userid in name_for_userid:
    return 'Hi %s!' % name_for_userid[userid] 
  else:
    return 'Hi there!'

Let’s see how this implementation of greeting() fares with our previous test cases:

>>> greeting(382) 
'Hi Alice!'

>>> greeting(33333333) 
'Hi there!'

Much better. We now get a generic greeting for unknown users and we keep the personalized greeting when a valid user ID is found.
使其更加通用化

But there’s still room for improvement. While this new implementation gives us the expected results and seems small and clean enough, it can still be improved. I’ve got some gripes with the current approach:

  • It’s inefficient because it queries the dictionary twice.
  • It’s verbose since part of the greeting string is repeated, for example.
  • It’s not Pythonic—the official Python documentation specifically recommends an “easier to ask for forgiveness than permission” (EAFP) coding style for these situations:

“This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false.”

A better implementation that follows the EAFP principle might use a try...except block to catch the KeyError instead of doing an explicit membership test:

def greeting(userid): 
  try:
    return 'Hi %s!' % name_for_userid[userid] 
  except KeyError:
    return 'Hi there'

This implementation is still correct as far as our initial requirements go, and now we’ve removed the need for querying the dictionary twice.

But we can still improve this further and come up with a cleaner solution. Python’s dictionaries have a get() method on them which supports a “default” parameter that can be used as a fallback value:

def greeting(userid):
  return 'Hi %s!' % name_for_userid.get(
        userid, 'there')

内置的字典支持get操作,可以直接设置在get失败后的返回值

When get() is called, it checks if the given key exists in the dictionary. If it does, the value for the key is returned. If it does not exist, then the value of the default parameter is returned instead. As you can see, this implementation of greeting still works as intended:
意思就是get方法被调用的时候,会检查被给定的键是否在字典中,如归在字典中,那么就会返回键对应的值。如果不在字典中,就返回默认的参数值

 >>> greeting(950) 
'Hi Bob!'

>>> greeting(333333) 
'Hi there!'

Our final implementation of greeting() is concise, clean, and only uses features from the Python standard library. Therefore, I believe it is the best solution for this particular situation.
嗯,果然作者还是更喜欢原生的方式

Key Takeaways
  • Avoid explicit key in dict checks when testing for membership.
  • EAFP-style exception handling or using the built-in get()
    method is preferable.
  • In some cases, the collections.defaultdict class from the
    standard library can also be helpful.

你可能感兴趣的:(Python Tricks - Dictionary Tricks(0))