上QQ阅读APP看书,第一时间看更新
2.14.3 捕获特定类型的异常
细分异常类型的存在,不仅可以让我们更准确地描述异常,还可以针对不同的类型进行不同的处理。在捕获异常的时候,我们可以指定特定的异常类型。
我们来设计一段代码:输入一个下标值,代码根据下标取出list中相应的元素,判断这个元素是否是奇数还是偶数。
def is_even_number(num_list, index): number = num_list[index] if number % 2 == 0: print('{} at position {} is even'.format(num_list[index], index)) return True else: print('{} at position {} is odd'.format(num_list[index], index)) return False
很显然,当指定的下标超出范围时,会有异常(IndexError类型)发生。
numbers = [21, 33, 34, 2, 99, 98] is_even_number(numbers, 100)
执行结果如下:
IndexError: list index out of range
当这类异常发生的时候,我们不希望程序就此崩溃,而是给用户一个清晰的提示。
def is_even_number(num_list, index): try: number = num_list[index] if number % 2 == 0: print('{} at position {} is even'.format(num_list[index], index)) return True else: print('{} at position {} is odd'.format(num_list[index], index)) return False except IndexError: print("ERROR: Invalid index {}".format(index)) return False numbers = [21, 33, 34, 2, 99, 98] is_even_number(numbers, 100) is_even_number(numbers, 2)
执行结果如下:
ERROR: Invalid index 100 34 at position 2 is even
如果list的值发生了变化,混入了一个字符串“奸细”。很显然,这个字符串不能进行数学计算。在这种情况下,我们可以设计多个except逻辑,分别针对不同的异常类型进行处理。
def is_even_number(num_list, index): try: number = num_list[index] if number % 2 == 0: print('{} at position {} is even'.format(num_list[index], index)) return True else: print('{} at position {} is odd'.format(num_list[index], index)) return False except IndexError: print("IndexError: Invalid index {}".format(index)) return False except TypeError: print("TypeError: Invalid value {} at index {}".format(number, index)) return False numbers = [21, 33, '66', 34, 2, 99, 98] is_even_number(numbers, 100) is_even_number(numbers, 3) is_even_number(numbers, 2) is_even_number(numbers, 1)
执行结果如下:
IndexError: Invalid index 100 34 at position 3 is even TypeError: Invalid value 66 at index 2 33 at position 1 is odd
如果不同类型的异常对应的异常处理逻辑是相同的,我们可以将处理逻辑合并,归总到一个except语句中。
def is_even_number(num_list, index): try: number = num_list[index] if number % 2 == 0: print('{} at position {} is even'.format(num_list[index], index)) return True else: print('{} at position {} is odd'.format(num_list[index], index)) return False except (IndexError, TypeError): print("Invalid data!") return False numbers = [21, 33, '66', 34, 2, 99, 98] is_even_number(numbers, 100) is_even_number(numbers, 3) is_even_number(numbers, 2) is_even_number(numbers, 1)
执行结果如下:
Invalid data! 34 at position 3 is even Invalid data! 33 at position 1 is odd
我们已经知道,异常类型有层次关系,比如,ZeroDivisionError是一种具体的Arith-meticError类型,而ArithmeticError是一种具体的Exception类型。如果一个try语句对应多个except分支,Python会根据分支的前后顺序依次判断类型,最先匹配的分支会被处理,后续的分支判断会被忽略,也就是说,最多只会有一个except的分支会得到处理。
在这个例子中,被抛出的异常被截获,进入ArithmeticError类型的逻辑分支被处理。
try: print(3 / 0) except ArithmeticError: print('ArithmeticError happened') except Exception: print('Exception happened')
执行结果如下:
ArithmeticError happened
如果我们调整except分支的顺序,把Exception类型的分支放在前面,因为Zero-DivisionError是Exception类型,所以程序逻辑会进入Exception的分支,后续更具体的ArithmeticError分支就没有机会得到处理。
try: print(3 / 0) except Exception: print('Exception happened') except ArithmeticError: print('ArithmeticError happened')
执行结果如下:
Exception happened