3、异常:
python使用被称为异常的特殊对象来管理程序执行期间发生的错误。
每 当 发 生 让 Python 不 知 所 措 的 错 误 时, 它 都 会 创 建 一 个 异 常 对 象。 如 果 你 编 写 了 处 理 该 异 常 的 代 码, 程 序 将 继 续 运 行;
如 果 你 未 对 异 常 进 行 处 理, 程 序 将 停 止, 并 显 示 一 个 traceback, 其 中 包 含 有 关 异 常 的 报 告。
异 常 是 使 用 try-except 代 码 块 处 理 的。 try-except 代 码 块 让 Python 执 行 指 定 的 操 作, 同 时 告 诉 Python 发 生 异 常 时 怎 么 办。 使 用 了 try-except 代 码 块 时, 即 便 出 现 异 常, 程 序 也 将 继 续 运 行: 显 示 你 编 写 的 友 好 的 错 误 消 息, 而 不 是 令 用 户 迷 惑 的 traceback。
3.1、处理ZeroDivisionError异常:
例1:division.py
print(5/0)
#报错:
Traceback (most recent call last):
File "division.py", line 1, in < module >
print( 5/ 0)
❶ ZeroDivisionError: division by zero
程序分析:
ZeroDivisionError是一个异常对象。python无法按你的要求做时,就会创建这种对象;我们可以根据这种信息对程序进行修改。
3.2、使用try-except代码块:
当 你 认 为 可 能 发 生 了 错 误 时, 可 编 写 一 个 try-except 代 码 块 来 处 理 可 能 引 发 的 异 常。 你 让 Python 尝 试 运 行 一 些 代 码, 并 告 诉 它 如 果 这 些 代 码 引 发 了 指 定 的 异 常, 该 怎 么 办。
例2:
try:
print(5/0)
except ZeroDivisionError:
print("You can't dvide by zero!")
程序分析:
我们将导致错误的代码行print(5/0)
放在了一个try代码块中。
如果try代码块中的代码运行起来没有问题,python将跳过except代码块;
如果try代码块中的代码导致了错误,python将查找这样的except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。
如果try-except代码块后面还有其他代码,程序将接着运行后面的代码。
3.3、使用异常避免奔溃:
发生错误时,如果程序还有工作没有完成,妥善处理错误就尤其重要。这种情况经常会出现要求用户提供输入的程序中能够妥善的处理无效输入,就能再提示用户提供有效输入,而不至于崩溃。
例3、division.py:创建一个只执行除法运算的简单计算器:
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: ")
if second_number = = 'q':
break
❸ answer = int( first_number) / int( second_number)
print( answer)
程序分析:
这个程序没有采取任何处理错误的措施,因此让它执行除数为0的出发运算时,它将崩溃。
#程序输出:
Give me two numbers, and I'll divide them.
Enter 'q' to quit.
First number: 5
Second number: 0
Traceback (most recent call last):
File "division.py", line 9, in < module >
answer = int( first_number) / int( second_number) ZeroDivisionError: division by zero
程序崩溃的坏处:
- 不懂技术的用户会被它们搞糊涂,而且如果用户怀有恶意,他会通过traceback获悉你不希望他们知道的信息。
- 他将知道你的程序文件的名称,还将看到部分不能正确运行的代码。
- 有时候,训练有素的攻击者可根据这些信息判断出可对你的代码发起什么样的攻击。
3.4、else代码块:
通过将可能引发错误的代码放在try-except代码块中,可提高这个程序抵御错误的能力。
例4 、下面示例还包含一个else代码块;依赖于try代码块成功执行的代码都应放在else代码块中:
print(" Give me two numbers, and I'll divide them.")
print(" Enter 'q' to quit.")
while True:
first_number = input("\n First 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
try-except-else代码块的工作原理如下:
- python尝试执行try代码块中的代码,只有可能引发异常的代码才需要放在try语句中。
- 有时候,有一些仅在try代码块成功执行时才需要运行的代码;这些代码应该放在else代码块中。
- except代码告诉python,如果它尝试运行try代码块中的代码是引发了指定的异常,该怎么办。
- 通过预测可能发生错误的代码,可编写健壮的程序,它们即便面临无效数据或缺少资源,也能继续运行,从而能够抵御无意的用户错误和恶意的攻击。
3.5、处理FileNotFoundError异常:
使用文件时,一种常见的问题是找不到文件:你要查找的文件可能在其他地方,文件名可能不正确或者这个文件根本不存在。对于这种情况,都可以使用try-except代码块以直观的方式进行处理。
例5:alice.py
filename = 'alice.txt'
with open(filename) as f_obj:
contents = f_obj.read()
#Python无法读取不存在的文件时引发的异常:
Traceback (most recent call last):
File "alice.py", line 3, in < module >
with open( filename) as f_obj:
FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
try—except异常改进:
filename = 'alice.txt'
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry,the file " + filename + "does not exist."
print(msg)
如果文件不存在,这个程序什么都不做,因此错误处理代码的意义不大。
下面来拓展这个示例,看看在你使用多个文件时,异常处理可提供什么样的帮助。
3.6、分析文本:
方法split()
,以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储在一个列表中。
title = "Alice in wonderland"
title.split()
['Alice','in','wonderland']
为计算小说book.txt包含多少个单词,我们将对整篇小说调用split()
,再计算得到的列表包含多少个元素,从而确定整本书大致包含多少个单词:
例6:
filename = 'book.txt'
try:
with open(filename,encoding = "UTF-8") as f_obj:
content = f_obj.read()
except FileNotFoundError:
msg = "Sorry,the file " + filename + " does not exist."
print(msg)
else:
#计算文件大致包含多少单词
words = contents.split()
num_worlds = len(words)
print("The file " + filename + " has about " + str(num_words) + " words.")
3.7、使用多个文件:
例7:word_count.py
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry,the file " + filename + " does not exist."
print(msg)
else:
#计算文件大致包含多少个单词
words = content.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) + " words.")
filename = 'book.txt'
count_worlds(filename)
filenames = ['alice.txt','siddhartha.txt','moby_dick.txt','little_women.txt']
for filename in filenames:
count_words(filename)
#输出结果:
The file alice.txt has about 29461 words.
Sorry, the file siddhartha.txt does not exist.
The file moby_dick.txt has about 215136 words.
The file little_women.txt has about 189079 words.
3.8、失败时一声不吭:
Python中的pass语句,可在代码块中使用它来让python什么都不要做。
def count_words( filename):
""" 计 算 一 个 文 件 大 致 包 含 多 少 个 单 词"""
try:
--snip--
except FileNotFoundError:
❶ pass
else:
--snip--
filenames = [' alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words( filename)
#输出结果:
The file alice.txt has about 29461 words. The file moby_dick.txt has about 215136 words. The file little_women.txt has about 189079 words.
pass
语句还充当了占位符,它提醒你在程序的某个地方什么都没有做,并且以后也许要在这里做些什么。
3.9、决定报告那些错误:
- python的错误处理结构让你能够细致地控制于用户分享错误信息的程度,要分享多少信息由你决定。
- 编写得很好且经过详尽测试的代码不容易出现内部错误,但只要程序依赖于外部因素,如用户输入、存在指定的文件、有网络链接,就有可能出现异常。
- 凭经验可判断出该在程序的什么地方包含异常处理块,以及出现错误时该向用户提供多少相关的信息。
本章代码示例来自:[美] Eric Matthes. Python编程:从入门到实践