异常
Python使用称之为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,都会创建一个异常对象。如果在代码中编写了处理这些异常的代码,程序将继续运行;如果未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的报告。
异常是使用try-except代码块处理的。try-except代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办,使用了try-except代码块让python执行指定的操作,同时告诉python发生异常时怎么办。使用try-except代码块时,即便出现异常,程序也将继续运行。显示你编写的友好的错误消息,而不是令用户迷惑的traceback反馈。
1.处理ZeroDivisionError异常
接下来就看一组导致Python引发异常的简单错误。我们都知道在数学中数字0不能做分母,然后呢,我们编写一段代码,看看python遇到分母为0的情况怎么处理:
division.py
print(5/0)
结果出错了:
Exception has occurred: ZeroDivisionError
division by zero
File "C:\Users\Administrator\Desktop\python\0503\division.py", line 1, in <module>
print(5/0)
在上面这种情况下,python将停止运行程序,并指出引发了那种异常,而我们可以根据这些信息对程序进行修改。
2.使用try-except代码块
当我们认为可能发生了错误时,可编写一个try-except代码块来处理可能引发的异常,让python尝试运行一些代码,并告诉它如果这些代码引发了指定的异常,该怎么处理。
处理ZeroDivisionError异常的try-except代码块类似于下面这样:
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
You can't divide by zero!
如果try代码块中的代码运行起来没有问题,Python将跳过except代码块;如果try代码块中的代码导致了错误,Python将查找这样的except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。这样,用户看到的是一条友好的错误消息,而不是traceback。
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)
结果在输入分母时,出现了错误:
我们可以想想,在我们使用智能设备上面的计算器app时,不小心把0作为了除数,然后计算器app卡死了或者把智能设备给搞崩溃了,给用户的体验效果多差劲,还不纷纷退货或者把客户反馈邮箱给塞爆啊,所以说程序崩溃很不好,并且那些懂点技术的用户,脑子里面有什么坏坏的小心思,通过traceback信息知道了程序文件的名称,并且还可以看到部分代码,那可就不好了。
4.else代码块
通过将可能引发错误的代码放在try-except代码块中,可提高这个程序抵御错误的能力。错误执行除法运算的代码行导致的,因此我们需要将它放到try-except代码块中。示例中还包含一个else代码块;依赖try代码块成功执行的代码都应放到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: ")
if second_number == 'q':
break
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("You can't divide by zero!")
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 zero!
First number: 5
Second number: 3
1.6666666666666667
First number: q
就像当我们在计算器中输入5/0时,计算器就会提示错误消息一样,我们在代码中也提示用户一条错误消息,然后再次让用户输入,用户不会看到app卡死的现象,提升了用户使用的友好性。
try-except-else代码块的工作原理大致如下:python尝试执行try代码块中的代码;只有可能引发异常的代码才需要放在try语句中。有时候,有一些仅在try代码块成功执行时才需要运行的代码;这些代码应该放在else代码块中。except代码块告诉python,如果它尝试运行try代码块中的代码时引发了指定的异常,该怎么办。
5.处理FileNotFoundError异常
使用文件时,一种常见的问题是找不到文件:要查找的文件可能在其他的地方、文件名可能不正确或者要查找的文件根本就不存在。对于所有这些情形,都可使用try-except代码块以直观的方式进行处理。
下面就看一个具体的例子,文件alice.txt是不存在的。
alice.py
filename = 'alice.txt'
with open(filename) as file_object:
contents = file_object.read()
执行结果,出现如下的错误提示:
执行结果报告了一个FileNotFoundError异常,这是python找不到要打开文件时创建的异常。在这个示例中,这个错误是函数open()导致的,因此要处理这个错误,必须将try语句放在包含open()的代码行之前。
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)
Sorry,the file alice.txt does not exist.
感觉这样的异常处理也没有什么意思是吧,不久是一个简短的提示吗?那我们下面就在举一个例子来看看。
6.分析文本
可以分析包含整本书的文本文件。下面来尝试提取陪伴我们很多人童年的童话(Alice in Wonderland)文本,并尝试计算它包含多少个单词,我们将使用方法split(),它根据一个字符串创建一个单词列表。我们暂时只对包含“Alice in Wonderland”的字符串调用方法split()的结果:
>>> title = "Alice in Wonderland"
>>> title.split()
['Alice', 'in', 'Wonderland']
方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。结果是一个包含字符串中所有单词的列表,虽然有些单词可能包含标点。为计算Alice in Wonderland包含多少个单词,我们将对整篇小说调用split(),再计算得到的列表包含多少个元素,从而确定整篇童话大致包含多少个单词:
filename = 'D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\\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)
else:
"""计算文件大致包含多少个单词"""
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) + " words. ")
output:
The file D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\alice.txt has about 29461 words.
在例子中我们使用了绝对路径,但是注意在路径的最后,文件名之前的反斜杠是两个。
7.使用多个文件
下面再多分析几本书。我们先将这个程序的大部分逻辑代码移到一个名为count_words()的函数中,这样呢,对多本书进行分析时将更容易:
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 = contents.split()
new_words = len(words)
print("The file " + filename + "has about " + str(new_words) + " words. ")
filenames = [
'D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\\alice.txt',
'siddhartha.txt','moby_dick.txt','D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\little_women.txt'
]
for filename in filenames:
count_words(filename)```
output:
```python
The file D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\alice.txthas about 29461 words.
Sorry,the file siddhartha.txt does not exist.
Sorry,the file moby_dick.txt does not exist.
The file D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\little_women.txthas about 189079 words.
代码中中间两个文件不存在,没有影响到后续代码的执行。
在代码中,使用try-except代码块提供了两个重要的优点:避免让用户看到traceback;让程序能够继续分析能够找到的其他文件。
8.失败时一声不吭
有的时候,并非每次发生异常的时候,都需要提示用户出现异常了,有可能就什么提示也没有(不说话,只是看看),在except代码块中就什么也不做,python有一个pass语句,可在代码块中使用它来让python什么都不做:
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
pass
else:
"""计算文件大致包含多少个单词"""
words = contents.split()
new_words = len(words)
print("The file " + filename + "has about " + str(new_words) + " words. ")
filenames = [
'D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\\alice.txt',
'siddhartha.txt','moby_dick.txt','D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\little_women.txt'
]
for filename in filenames:
count_words(filename)
output:
The file D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\alice.txthas about 29461 words.
The file D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\little_women.txthas about 189079 words.
pass语句还充当了占位符,它提醒在程序中的某个地方射门都没有做,就像在C语言中,什么也不做时就摆放一对括号,必须要有括号,当然在C语言中一般时不建议使用这样什么也不做的空语句,除非有特殊的应用需求。
练习:
print("Wellcome use calculate!")
while True:
value = input("please enter value: ")
if value == 'q':
break
value = int(value)
print(value)
output:发生了如下的错误:
怎么处理呢?属于ValueError.
print("Wellcome use calculate!")
while True:
value = input("please enter value: ")
if value == 'q':
break
try:
value = int(value)
except ValueError:
pass
else:
print(value)
output:这次可以了
Wellcome use calculate!
please enter value: 1
1
please enter value: 2
2
please enter value: 3
3
please enter value: 4
4
please enter value: w
please enter value: e
please enter value: r
please enter value: t
please enter value: q
练习:
filename = 'D:\python\《Python编程》源代码文件-更新\《Python编程》源代码文件\chapter_10\\alice.txt'
value = 0
try:
with open(filename) as f:
contents = f.read()
words = contents.split()
count = len(words)
print(count)
print(contents.lower().count('the'))
print(contents.rstrip())
except FileNotFoundError:
pass