Python基础篇(十)-- 异常处理

        在程序运行过程中,经常会遇到各种各样的错误,这些错误统称为“异常”。这些异常有的是由于开发者将关键字敲错导致的,这类错误多数产生的是SyntaxError: invalid syntax(无效的语法),这将直接导致程序不能运行。这类异常是显式的,在开发阶段很容易被发现。还有一类是隐式的,通常和使用者的操作有关。

        异常处理在任何一门编程语言里都是值得关注的一个话题,良好的异常处理可以让你的程序更加健壮,清晰的错误信息更能帮助你快速修复问题。在Python中,和不部分高级语言一样,使用了try/except/else/finally语句块来处理异常。

        Python有两种错误很容易辨认:语法错误和异常。Python的语法错误或者称之为解析错,就是解析代码时出现的错误。当代码不符合Python语法规则时,Python解释器在解析时就会报出SyntaxError语法错误,与此同时还会明确指出最早探测到错误的语句。如少了冒号,或者混用中英文符号的等等。即便 Python程序的语法是正确的,在运行它的时候,也有可能发生错误。运行期检测到的错误被称为异常。大多数的异常都不会被程序处理,都以错误信息的形式展现。例如除数为 0、年龄为负数、数组下标越界等。下图列出常见异常:


图1 Python中常见异常

1 异常处理

        当一个程序发生异常时,代表该程序在执行时出现了非正常的情况,无法再执行下去。默认情况下,程序是要终止的。如果要避免程序退出,可以使用捕获异常的方式获取这个异常的名称,再通过其他的逻辑代码让程序继续运行,这种根据异常做出的逻辑处理叫作异常处理

        开发者可以使用异常处理全面地控制自己的程序。异常处理不仅仅能够管理正常的流程运行,还能够在程序出错时对程序进行必的处理。大大提高了程序的健壮性和人机交互的友好性。

1.1 try/except

        异常捕捉通常使用try/except语句,其基本语法结构如下图所示:

# Mutiple exception in one line
try:
    print(a / b)
except (ZeroDivisionError, TypeError) as e:
    print(e)

        try块有且仅有一个,但except代码块可以有多个,且每个except块都可以同时处理多种异常。当程序发生不同的意外情况时,会对应特定的异常类型,Python解释器会根据该异常类型选择对应的except块来处理该异常。

        try语句的执行流程如下;

  • 首先,执行try子句(在关键字try和关键字except之间的语句)。
  • 如果没有异常发生,忽略except子句,try子句执行后结束。
  • 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。如果异常的类型和except之后的名称相符,那么对应的except子句将被执行,这个过程被称为处理异常。
  • 如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中,且程序运行终止,Python 解释器也将退出。

        温馨提示: 不管程序代码块是否处于try块中,甚至包括 except块中的代码,只要执行该代码块时出现了异常,系统都会自动生成对应类型的异常。但是,如果此段程序没有用 try包裹,又或者没有为该异常配置处理它的except块,则Python解释器将无法处理,程序就会停止运行;反之,如果程序发生的异常经try捕获并由except处理完成,则程序可以继续执行。

1.2 try/except…else

        在原本的try except结构的基础上,Python异常处理机制还提供了一个else块,也就是原有try except语句的基础上再添加一个else块,即try except else结构。如果使用else块,那么必须放在所有的except子句之后。

        使用else包裹的代码,只有当try块没有捕获到任何异常时,才会得到执行;反之,如果try块捕获到异常,即便调用对应的except处理完异常,else块中的代码也不会得到执行。

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

        使用else子句比把所有的语句都放在try子句里面要好,这样可以避免一些意想不到,而except又无法捕获的异常。

1.3 try-finally

        Python异常处理机制还提供了一个finally语句,通常用来为try块中的程序做扫尾清理工作。

        注意,和else语句不同,finally只要求和try搭配使用,而至于该结构中是否包含except以及else,对于 finally不是必须的(else必须和try except搭配使用)。

        在整个异常处理机制中,finally语句的功能是:无论try块是否发生异常,最终都要进入finally语句,并执行其中的代码块。

        基于finally语句的这种特性,在某些情况下,当try块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就放在finally块中。
Python垃圾回收机制,只能帮我们回收变量、类对象占用的内存,而无法自动完成类似关闭文件、数据库连接等这些的工作。

def main():
    f = None
    try:
        f = open('myfile.txt', 'r', encoding='utf-8')
        print(f.read())
    except FileNotFoundError:
        print('无法打开指定的文件!')
    except LookupError:
        print('指定了未知的编码!')
    except UnicodeDecodeError:
        print('读取文件时解码错误!')
    except Exception as e:
        print('Unexpected Error: {}'.format(e))
    finally:
        if f:
            f.close()
main()

1.4 抛出异常

        如果你需要自主抛出异常一个异常,可以使用raise关键字,等同于C#和Java中的throw,有如下三种常用的用法:

  • raise:单独一个raise。该语句引发当前上下文中捕获的异常(比如在except块中),或默认引发RuntimeError异常。
  • raise异常类名称:raise后带一个异常类名称,表示引发执行类型的异常。
  • raise异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:",repr(e))
    raise

1.5 自定义异常

        Python中自定义自己的异常类型非常简单,只需要要从Exception类继承即可(直接或间接):

class SomeCustomException(Exception):
    pass

class AnotherException(SomeCustomException):
    pass

        一般你在自定义异常类型时,需要考虑的问题应该是这个异常所应用的场景。如果内置异常已经包括了你需要的异常,建议考虑使用内置的异常类型。比如你希望在函数参数错误时抛出一个异常,你可能并不需要定义一个InvalidArgumentError,使用内置的ValueError即可。

补充:

        在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题。

        捕获异常时,有 2 种方式可获得更多的异常信息,分别是:

  • 使用sys模块中的exc_info方法;
  • 使用traceback模块中的相关函数。

        了解更多请参考,Python sys.exc_info()方法:获取异常信息traceback模块:获取异常信息

        Python assert(断言)用于判断一个表达式,在表达式条件为false的时候触发异常。

        断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况。

assert 1 == 2   # 判断条件为False,抛出异常

        下面是Python中常见的抛出异常:

BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长路漫漫2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值