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

Chapter 8 错误与异常

8.1 语法错误

语法错误属于Python常见错误(Error)的一种。语法错误指的是程序的写法不符合编程语言规定。常见语法错误有:

(1)拼写错误

关键字、变量名、函数名拼写错误。关键字错误时会在运行时给出SyntaxError的提示,变量名、函数名拼写错误则提示NameError。

  • 例:
>>> for i in range(3):
	printt(i)

	
Traceback (most recent call last):
  File "<pyshell#2>", line 2, in <module>
    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 "<pyshell#5>", line 1, in <module>
    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.5

First number: q

这样遇到异常,程序依然能够继续运行,用户也看不到traceback的内容。

(2)FileNotFoundError异常处理

找不到文件会引发FileNotFoundError异常。

  • 例:
>>> file=open('eeee.txt','r')

Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    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) * 2

def 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) * 2

def main():
    bar('0')

main()

执行后结果如下:

Traceback (most recent call last):
  File "err.py", line 11, in <module>
    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的异常也属于类,所有异常类型都由BaseException类派生的。常见异常类型和继承关系可参考文档:

https://docs.python.org/3/library/exceptions.html#exception-hierarchy

上文提到except的两种用法;:只使用except和使用except...as...。主要用法如下:

在这里插入图片描述
可见except可以捕获所有异常或指定的异常。

8.3 记录异常-logging

Python内置的logging模块可用于记录异常信息。

  • 例:
  • 定义和调用
import logging

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def 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):
    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 "err_raise.py", line 10, in <module>
    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 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise

bar()

输出

ValueError!
Traceback (most recent call last):
  File "err_reraise.py", line 14, in <module>
    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 "<pyshell#1>", line 1, in <module>
    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 "<pyshell#6>", line 1, in <module>
    foo('0')
  File "<pyshell#4>", 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教程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值