Python|【Python】Python学习(十一)错误与异常


Python学习(十一)错误与异常

  • Chapter 8 错误与异常
    • 8.1 语法错误
      • (1)拼写错误
      • (2)不符合语法规范
      • (3)缩进错误
    • 8.2 异常的处理-`try-except`
      • (1)ZeroDivisionError异常处理
      • (2)FileNotFoundError异常处理
      • (3)跨越多层调用
      • (4)常见的异常及其处理
    • 8.3 记录异常-`logging`
    • 8.4 抛出异常
      • (1)`raise`语句
      • (2)`assert`语句

Chapter 8 错误与异常 8.1 语法错误 语法错误属于Python常见错误(Error)的一种。语法错误指的是程序的写法不符合编程语言规定。常见语法错误有:
(1)拼写错误
关键字、变量名、函数名拼写错误。关键字错误时会在运行时给出SyntaxError的提示,变量名、函数名拼写错误则提示NameError。
  • 例:
>>> for i in range(3): printt(i) Traceback (most recent call last): File "", line 2, in printt(i) NameError: name 'printt' is not defined

这里函数名print拼写错误写成printt ,给出了NameError的错误提示。
(2)不符合语法规范
如缺少括号、冒号等符号,表达式书写错误。
>>> for i in range(3) print(i) SyntaxError: invalid syntax

缺少冒号,出现SyntaxError语法错误的提示。
(3)缩进错误
4个空格作为一个缩进,或用Tab实现。符合Python语法并方便阅读。
8.2 异常的处理-try-except 异常(Exception) 指的是Python中的特殊对象,用于管理程序执行期间发生的错误。也就是错误发生时,Python会创建一个异常对象。
若异常被处理,程序将继续运行;若没被处理,则停止程序并显示一个traceback,包含有关异常的报告。
(1)ZeroDivisionError异常处理
异常的处理一般使用try-except 代码块,执行指定操作。
  • 例:
>>> print(5/0) Traceback (most recent call last): File "", line 1, in print(5/0) ZeroDivisionError: division by zero

Traceback指出错误ZeroDivisionError是一个异常对象。下面使用try-except 代码块进行处理:
>>> try: print(5/0) except ZeroDivisionError: print("You can't divide by zero!") You can't divide by zero!

try语句的部分出现异常,则执行except语句的部分。
可以要求用户提供有效输入,避免异常带来崩溃。将成功执行的代码放在else代码块中:
print("Give me two numbers, and I'll divide them.") print("Enter 'q' to quit.")while True: first_number = input("\nFirst number: ") if first_number == 'q': break second_number = input("Second number: ") try: answer = int(first_number) / int(second_number) except ZeroDivisionError: print("You can't divide by 0!") else: print(answer)

输出
Give me two numbers, and I'll divide them. Enter 'q' to quit.First number: 5 Second number: 0 You can't divide by 0!First number: 5 Second number: 2 2.5First number: q

【Python|【Python】Python学习(十一)错误与异常】这样遇到异常,程序依然能够继续运行,用户也看不到traceback的内容。
(2)FileNotFoundError异常处理
找不到文件会引发FileNotFoundError异常。
  • 例:
>>> file=open('eeee.txt','r')Traceback (most recent call last): File "", line 1, in file=open('eeee.txt','r') FileNotFoundError: [Errno 2] No such file or directory: 'eeee.txt'

找不到名为eeee.txt的文件,采用try-except代码块进行处理。用except...as...:语句,将报错存储在变量中。
  • 输出错误
try: file = open('eeee.txt','r') except Exception as e: print(e) [Errno 2] No such file or directory: 'eeee.txt'

  • 处理错误
try: file = open('eeee.txt','r+') except Exception as e: print(e) response = input('Do you want to create a new file?:') if response == 'y': file = open('eeee.txt','w') else: pass else: file.write('ssss') file.close()

没找到文件,因此报错:No such file or directory;给出解决方法,输入y则新建一个文件(写入类型),否则不进行任何操作并跳出程序。再次运行后,文件已被找到,字符串ssss被写入。
(3)跨越多层调用
使用try...except代码块进行异常捕获的好处在于,它可以实现跨越多层调用。
  • 例:
  • 定义
def foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): try: bar('0') except Exception as e: print('Error:', e) finally: print('finally...')

  • 调用
>>> main() Error: division by zero finally...

函数main()调用bar()bar()调用foo(),结果foo()出错了,这时,只要main()捕获到了,就可以处理。这样就不需要在每个可能出错的地方去捕获异常,只需在合适的层次进行异常捕获。
如果异常未被捕获,则会沿着栈往上层抛出,直至被Python解析器捕获并打印错误信息,程序退出:
def foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): bar('0')main()

执行后结果如下:
Traceback (most recent call last): File "err.py", line 11, in main() File "err.py", line 9, in main bar('0') File "err.py", line 6, in bar return foo(s) * 2 File "err.py", line 3, in foo return 10 / int(s) ZeroDivisionError: division by zero

层层分析调用栈信息,最后定位到错误的位置在return 10 / int(s),产生了ZeroDivisionError的异常。
(4)常见的异常及其处理
常见的异常如下:
Python|【Python】Python学习(十一)错误与异常
文章图片

Python的异常也属于类,所有异常类型都由BaseException类派生的。常见异常类型和继承关系可参考文档:
https://docs.python.org/3/library/exceptions.html#exception-hierarchy
上文提到except的两种用法; :只使用except和使用except...as...。主要用法如下:
Python|【Python】Python学习(十一)错误与异常
文章图片

可见except可以捕获所有异常或指定的异常。
8.3 记录异常-logging Python内置的logging模块可用于记录异常信息。
  • 例:
  • 定义和调用
import loggingdef foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): try: bar('0') except Exception as e: logging.exception(e)main() print('END')

  • 执行
ERROR:root:division by zero Traceback (most recent call last): File "err_logging.py", line 11, in main bar('0') File "err_logging.py", line 7, in bar return foo(s) * 2 File "err_logging.py", line 4, in foo return 10 / int(s) ZeroDivisionError: division by zero END

异常信息打印后继续执行,程序可以正常退出。此外logging可以将错误记录到日志文件中。
8.4 抛出异常 (1)raise语句
上文提到的异常均是因错误引发的异常。错误Python提供raise语句来引发指定的异常,并向异常传递数据。每次执行语句,只能抛出一次异常。使用方式如下:
raise [ExceptionName[(reason)]

三种用法:
raise 抛出上下文捕获的异常;
raise 异常类名称 抛出指定类型的异常;
raise异常类名称(描述信息):抛出指定类型的异常,并附带其描述信息。
  • 例1:
    需要自定义一个异常类,选择好继承关系,再使用raise语句抛出一次的实例。
class FooError(ValueError): passdef foo(s): n = int(s) if n == 0: raise FooError('invalid value: %s' % s) return 10 / nfoo('0')

Traceback (most recent call last): File "err_raise.py", line 10, in foo('0') File "err_raise.py", line 7, in foo raise FooError('invalid value: %s' % s) FooError: invalid value: 0

  • 例2:
尽量选择Python内置的错误类型(如ValueErrorTypeError
def foo(s): n = int(s) if n==0: raise ValueError('invalid value: %s' % s) return 10 / ndef bar(): try: foo('0') except ValueError as e: print('ValueError!') raisebar()

输出
ValueError! Traceback (most recent call last): File "err_reraise.py", line 14, in bar() File "err_reraise.py", line 9, in bar foo('0') File "err_reraise.py", line 4, in foo raise ValueError('invalid value: %s' % s) ValueError: invalid value: 0

这里bar()函数的raise语句不带参数,将当前错误原样抛出。捕获异常的目的是记录,便于后续追踪。
(2)assert语句
assert(断言)可以理解为raise的简化。其用于判断一个表达式,在表达式条件为false的时候触发异常。条件不满足的时候直接返回错误。
使用方法:
assert expression [, arguments]

  • 例1:
>>> assert True >>> assert False Traceback (most recent call last): File "", line 1, in assert False AssertionError

false时触发异常。
  • 例2:
>>> def foo(s): n = int(s) assert n != 0,'n is zero!' return 10 / n>>> foo('0') Traceback (most recent call last): File "", line 1, in foo('0') File "", line 3, in foo assert n != 0,'n is zero!' AssertionError: n is zero!

raise语句的例子进行修改。这里assert的意思是,表达式n != 0是True,否则,断言失败,触发AssertionError
通常assert语句用作测试代码的有效性,若不符合要求则触发异常,中断程序。要关闭程序中的assert语句,启动Python解释器的-O参数,则使用python -O即可关闭。
$ python -O err.py Traceback (most recent call last): ... ZeroDivisionError: division by zero

====================================================================
Python学习的内容参考
《Python编程:从入门到实践》-[美] Eric Matthes
《21天学通PYTHON》
莫烦Python
廖雪峰的Python教程

    推荐阅读