python学习笔记(十二)错误处理

    技术2022-07-11  123

    错误处理

    在程序运行过程中,如果发出了错误,可以事先约定返回一个错误代码,这样就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。 比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1. 用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,调用者必须用大量代码判断是否出错。

    def foo(): r = some_function() if r==(-1): return (-1) # do something return r def bar(): r = foo() if r==(-1): print('Error') else: pass

    一旦出错,还要一级一级的上报,直到某个函数可以处理该错误 (比如,给用户输出一个错误信息) 所以高级语言通常都内置了一套try…except…finally…的错误处理机制,python也不例外。

    try 让我们用一个例子来看看try的机制

    try: print('try...') r = 10 / int('a') print('result:', r) except ValueError as e: print('ValueError:', e) except ZeroDivisionError as e: print('ZeroDivisionError:', e) finally: print('finally...') print('END')

    try运行代码,except捕获相应错误,finally最终执行

    try: foo() except ValueError as e: print('ValueError') except UnicodeError as e: print('UnicodeError')

    第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。 所有错误都是从BaseException类派生的,常见的错误类型和继承关系:https://docs.python.org/3/library/exceptions.html#exception-hierarchy try。。。except捕获错误可以跨越多层调用,比如main()调用bar(),bar()调用foo(),结果foo()出错了,这时,只要main()捕获到了 ,就可以处理

    def foo(s): return 10 / int(s) def bar(s): return foo(s) * 2 def main(): try: bar('0') except Exception as e: print('Error:', e) finally: print('finally...')

    只要在合适的层次去捕获错误就可以了,不用次次捕获。

    记录错误 如果不捕获错误,自然可以让Python解释器打印错误,但程序也被结束了。 Python内置的logging模块可以非常容易地记录错误信息:

    抛出错误 因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误不是凭空产生的,而是有意创建并抛出的。Python的内置函数就会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。 如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误实例。

    class FooError(ValueError): #错误类 pass def foo(s): n = int(s) if n==0: #主动捕获错误 raise FooError('invalid value: %s' %s) #主动抛出错误 return 10 / n foo('0')

    结果:

    Traceback (most recent call last): File "G:/zrx/demoproject/demo1.py", line 681, in <module> foo('0') File "G:/zrx/demoproject/demo1.py", line 679, in foo raise FooError('invalid value: %s' %s) __main__.FooError: invalid value: 0 Process finished with exit code 1

    另一种错误的捕获方式: 定义错误类然后 主动raise

    class FooError(ValueError): #错误类 pass def foo(s): n = int(s) if n==0: #主动捕获错误 raise FooError('invalid value: %s' %s) #主动抛出错误 return 10 / n foo('0')

    最后 一种错误处理:捕获打印,不处理,只抛出

    def foo(s): n = int(s) if n==0: raise ValueError('invalid value: %s' % s) return 10 / n def bar(): try: foo('0') except ValueError as e: print('ValueError') raise bar()

    上面的代码中,在bar()函数内,我们明明已经捕获了错误,但是,打印一个ValueError后,又把错误通过raise语句抛出去了。 捕获错误目的只是记录 一下 ,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,最恰当的方式是继续 往上抛,让顶层调用者处理该错误。 raise语句 如果 不带参数,就会把当前错误原样抛出。 此外,在except中raise一个Error,还可以把一种类型的错误转化成另一种:

    try: 10 / 0 except ZeroDivisionError: raise ValueError('input error!')

    只要是合理的转换逻辑即可,但绝不应把一个IOError转换成不相干的错误,类似ValueError。 常见错误父子关系:https://docs.python.org/3/library/exceptions.html#exception-hierarchy

    Processed: 0.008, SQL: 9