Click here for the first post, which contains the context of this series.
Item #16: Prefer get over in and KeyError to handle missing dictionary keys.
Prefer
my_result = my_dict.get(my_key, my_default_value)
over both
if my_key in my_dict:
my_result = my_dict[my_key]
else:
my_result = my_default_value
and
try:
my_result = my_dict[my_key]
except KeyError:
my_result = my_default_value
Item #17: Prefer defaultdict over setdefault to handle missing items in internal state.
Prefer
my_dict = defaultdict(set)
my_dict[my_key].add(my_value)
over
my_dict = {}
my_dict.setdefault(my_key, set()).add(my_value)
Note that setdefault always executes its second argument and is prone to difficult exception handling.
Item #18: Know how to construct key-dependent default values with __missing__.
If you need to handle a missing item by calling a function that:
- takes at least one argument and
- should be called only when necessary,
then defaultdict and setdefault, respectively, will not work. Instead, do something like this:
class MyDict:
def __missing__(self, key):
try:
value = open(key, 'a+b')
self[key] = value
return value
except OSError:
print(f'failed to open {key}')
raise
my_dict = MyDict()
file = my_dict[key]
Item #19: Never unpack more than three variables when functions return multiple values.
Avoid doing this since an accidental reorder is not difficult:
minimum, maximum, average, median, count = get_statistics(data)
Item #20: Prefer raising exceptions to returning None.
This looks like it works:
def careful_divide(a, b):
return a / b if b != 0 else None
c = careful_divide(a, b)
if not c:
print('division by 0')
But if a, b = 0, 1, then division by 0 is printed, which is undesired behavior. Instead, do something like this:
def careful_divide(a, b):
try:
return careful_divide(a, b)
except ZeroDivisionError:
raise ValueError('division by 0')