I'm confused about the Pythonic approach to Exception handling in a function. As an example, I have a function calc_mean() which is to calculate the mean of a list of numbers. (I know that the statistics module provides a mean() function, but for learning purposes I'm trying to building my own statistics functions).
One obvious problem that can occur is that the function is passed an empty list. I would like to ask which of the following approaches is most Pythonic:
Do nothing here, let the calling function deal with it
def calc_mean(a_list): return sum(a_list)/len(a_list)Look before you Leap with
if-elseand returnNoneif list is emptydef calc_mean1(a_list): if a_list: return sum(a_list)/len(a_list) else: return NoneLook before you Leap with
if-elseand raise aValueErrorif list is emptydef calc_mean2(a_list): if a_list: return sum(a_list)/len(a_list) else: raise ValueError("Can't calculate the mean of an empy list")Easier to ask for Forgiveness with
try-except, raise aValueErrorif list is emptydef calc_mean3(a_list): try: return sum(a_list)/len(a_list) except ZeroDivisionError: raise ValueError("Can't calculate the mean of an empy list")Easier to ask for Forgiveness with
try-except, raise aValueErrorwith afromif list is emptydef calc_mean4(a_list): try: return sum(a_list)/len(a_list) except ZeroDivisionError: raise ValueError("Can't calculate the mean of an empy list") from ZeroDivisionError
My gut feeling is that approaches 4 or 5 are the correct ones, and certainly make it easier to deal with multiple exceptions (e.g. TypeError due to non-numeric elements in the list). However, part of me wonders if approach 1 is preferable as it will calculate and return the mean if it can, or otherwise raise an exception which the calling function should handle.