异常:
python使用称为异常的特殊类对象来管理程序执行期间发生的错误,每当发生让python不知所措的错误时,他都会创建一个异常的对象。
如果你编写了处理该异常的代码,程序将继续进行,如果未对异常进行处理,程序将停止并显示traceback,其中包含有关异常的报告。
异常是使用 try-except 代码块处理的。try-except 代码块让 Python 执行指定的操作,同时告诉python发生异常时怎么办,使用try-except代码块时,即便出现异常,程序也将继续运行,显示你编写的友好的错误消息,而不是令用户迷惑的 traceback。
处理ZeroDivisionErro:
举例:
我们早已在数学中学过,0不能在分母的位置,但还是让python执行如下程序:
print(5/0)
输出结果产生了traceback:
Traceback (most recent call last): File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 14, in <module> print(5/0) ZeroDivisionError: division by zero
在上述 traceback中,指出的错误 ZeroDivisionError 是个异常对象。Python 无法按你的要求做时,就会创建这种对象。在这种情况下,**Python 将停止运行程序,并指出引发了哪种异常,**而我们可根据这些信息对程序进行修改。下面来告诉 Python,发生这种错误时怎么办。这样,如果再次发生此类错误,我们就有备无患了。
使用try-except代码块:
当你认为可能发生错误时,可编写一个代码块try-except代码块来处理可能引发的异常,你让python尝试运行一些代码,并告诉它如果这些代码引发了指定的异常该怎么办。
处理ZeroDivisionErro异常的try-except代码块类似于下面这样:
try: print(5/0) except ZeroDivisionError: print("you can't divide by zero")
将导致错误的代码行print(5/0)放在一个try代码块中,如果try代码块中的代码运行起来没有问题,python将跳过execpt代码块,如果try代码块中的代码导致了错误,python将查找与之匹配的except代码块并运行其中的代码。
you can't divide by zero
如果except代码块后面还有其他代码块,程序将接着运行,因为已经告诉python如何处理这种错误。
使用异常避免崩溃:
发生错误时,如果程序还有工作尚未完成,妥善处理错误就显得尤其重要,这种情况经常会出现在要求用户提供输入的程序中,如果程序能够妥善的处理无效输入,就能再提示用户提供有效输入,而不至于崩溃。
举例:
该程序是实现求两个数的商
print("Give me two numbers,and I'll divide them.") print("enter 'q' to quit") while True: fist_number=input("\nfist number:") if fist_number=='q': break second_number=input("\nsecond number:") if second_number=='q': break answer=int(fist_number)/int(second_number) print(answer)
由于对被除数为0的这种情况未作任何处理,所以当被除数为0时,会出现异常
Give me two numbers,and I'll divide them. enter 'q' to quit fist number:19 second number:0 Traceback (most recent call last): File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 24, in <module> answer=int(fist_number)/int(second_number) ZeroDivisionError: division by zero
程序崩溃可不好,但让用户看到 traseback 也不是个好主意。不懂技术的用户会被搞糊涂。怀有恶意的用户还会通过 traceback 获悉你不想他知道的信息。例如,他将知道你的程序文件的名称,还将看到部分不能正确运行的代码。有时候,训练有素的攻击者可根据这些信息判断出可对你的代码发起什么样的攻击。
那么应该怎么妥善解决这个问题呢?
答案是:使用try-except代码块,那么具体怎么操作呢?
else代码块:
通过将可能引发错误的代码块放入try-except代码块中,可提高程序抵御错误的能力。
举例:
while True: fist_number=input("\nfist number:") if fist_number=='q': break second_number=input("\nsecond number:") if second_number=='q': break try: answer=int(fist_number)/int(second_number)#可能引发程序崩溃的代码 except ZeroDivisionError: print("you can't divide by 0!")#try语句后程序未成功运行,友情提示错误的消息内容 else: print(answer)#try语句后程序成功运行的代码
Give me two numbers,and I'll divide them. enter 'q' to quit fist number:12 second number:0#当被除数是0 you can't divide by 0!#会输出良好的友情提醒而不是程序崩溃
try-except-else代码块的工作原理大致如下:
python尝试执行try代码块中的代码,只有可能引发错误的代码才需要放在try语句中,有时候,有一些仅在try代码块成功执行时才需要运行的代码,这些代码应放在else代码块中,except代码块告诉python,如果尝试运行try代码块时引发了指定的异常该怎么办。
处理FileNotFoundError异常:
使用文件时,一种常见的问题就是找不到文件,查找的文件可能在其他地方,文件名可能不正确,或者这个文件根本不存在,对于所有这些情况,都可使用try-except代码块以直观的方式进行处理。
举例:
下面我们通过读取系统不存在的文件:
with open("789.txt",encoding='utf-8') as f: f.read()
python无法读取不存在的文件,因此它将引发异常:
Traceback (most recent call last): File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 30, in <module> with open("789.txt",encoding='utf-8') as f: FileNotFoundError: [Errno 2] No such file or directory: '789.txt'
上述中的Traceback的最后一行报告了FileNotFoundError异常,这是python找不到要打开的文件时创建的异常,在本例中,是由open函数导致的,因此,要处理这个错误,必须将try语句放在包含open()的代码行之前:
优化之后的代码:
try: filename='789.txt' with open("filename",encoding='utf-8') as f: f.read() except FileNotFoundError: print(f"sorry,the file{filename}does not exist")
如下图所示,当文件不存在时,python此时并没有引发异常,而是输出一条提示的信息。
sorry,the file789.txtdoes not exist
如果文件不存在,这个程序就什么也做不了,错误处理代码的意义不大。
当我们需要处理多个文件的时候,异常处理可提供的帮助:
分析文本:
你可以分析包含整本书的文本文件。
举例:
filename="123.txt" try: with open(filename,encoding="utf-8") as f: contents=f.read()#运行成功,执行else代码块后面的语句 except FileNotFoundError: print(f"sorry,the file{filename} does not exist") else: words=contents.split()#以空格作为标记符号,将字符串分隔开 num_words=len(words)#计算字符串的长度 print(f"the file {filename} has about {num_words} words")
the file 123.txt has about 98 words
123.txt内容如下:
Currently,there is a widespread concern over (the issue that)__作文题目 . It is really an important concern to every one of us. As a result,we must spare no efforts to take some measures to solve this problem.As we know that there are many steps which can be taken to undo this problem. First of all,__途径一 _In addition, another way contributing to successfully solving the problem is 途径二Above all, to solve the problem of ___作文题目,we should find a number of various ways. But as far as I am concerned, I would prefer to solve the problem in this way,that is to say, 方法
使用多个文件:
下面同时多分析几本书:
在此之前我们先将这个程序的代码移到一个名为count_words的函数中,这样,对多本书的分析就会更加方便。
def count_words(filename):#计算一个文件里面大致包含多少词 try: with open(filename,encoding="utf-8") as f: contents=f.read() except FileNotFoundError: print(f"sorry,the file{filename} does not exist") else: words=contents.split() num_words=len(words) print(f"the file {filename} has about {num_words} words") fliename=["123.txt","456.py"]#将多个文本存储在一个列表中 for filename in fliename:#使用for循环对其进行遍历 count_words(filename)#依次调用函数对不同文本的词进行统计
the file 123.txt has about 14 words the file 456.py has about 42 words
如果其中的某个文件不存在呢?
使用try-except代码块的效果:
def count_words(filename):#计算一个文件里面大致包含多少词 try: with open(filename,encoding="utf-8") as f: contents=f.read() except FileNotFoundError: print(f"sorry,the file{filename} does not exist") else: words=contents.split() num_words=len(words) print(f"the file {filename} has about {num_words} words") fliename=["123.txt","789.py","456.py"]#将多个文本存储在一个列表中 for filename in fliename:#使用for循环对其进行遍历 count_words(filename)#依次调用函数对不同文本的词进行统计
the file 123.txt has about 14 words sorry,the file789.py does not exist the file 456.py has about 42 words
不使用try-except代码块的效果:
def count_words(filename):#计算一个文件里面大致包含多少词 # try: with open(filename,encoding="utf-8") as f: contents=f.read() words=contents.split() num_words=len(words) print(f"the file {filename} has about {num_words} words") fliename=["123.txt","789.py","456.py"] for filename in fliename: count_words(filename)
the file 123.txt has about 14 words Traceback (most recent call last): File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 41, in <module> count_words(filename) File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 32, in count_words with open(filename,encoding="utf-8") as f: FileNotFoundError: [Errno 2] No such file or directory: '789.py'
通过对比上述两个的执行效果,我们发现使用try_except代码块,在某文件不存在的情况下,编译器不仅不会发生异常,而且不存在文件后面的文件依然会被编译器进行分析,而不使用try-except代码块,在某文件不存在的情况下,traceback不仅被完整显示,而且后面的文本编译器不会进行分析。
这样对比,是不是觉得使用try——except代码块更友好一些?
静默失败:
在上面的示例中,我们告诉用户有一个文件找不到,但并非每次产生异常都要告诉用户,有时候你希望程序在发生异常时保持静默,就像什么都没有发生一样继续运行,要让程序静默失败,可像通常编写try代码块那样,但在except代码块中明确告诉python什么都不要做,python有一个pass语句,可让python在代码块中什么都不要做。
举例:
def count_words(filename):#计算一个文件里面大致包含多少词 try: with open(filename,encoding="utf-8") as f: contents=f.read() except FileNotFoundError: pass#当出现异常时,python将不会告诉用户任何东西 else: words=contents.split() num_words=len(words) print(f"the file {filename} has about {num_words} words") fliename=["123.txt","789.py","456.py"]#将多个文本存储在一个列表中 for filename in fliename:#使用for循环对其进行遍历 count_words(filename)#依次调用函数对不同文本的词进行统计
相比于前面的程序,这个程序唯一不同的地方就是在except代码块后面使用的是pass语句,现在,当
出现FileNotFoundError异常时,将执行except代码块中的代码,但什么都不会输出,这种错误发生时,不会出现traceback,也没有任何输出语句,用户将看到存在的文件输出的内容,但不会看到有文件没有被找到的内容。
the file 123.txt has about 14 words the file 456.py has about 42 words
pass语句还充当了占位符,提醒你在程序的某个地方什么都没做,并且以后需要在这里做些什么。
决定报告哪些错误
该在什么情况下向用户报告错误?
如果用户知道要分析哪些文件,他们可能希望在有文件却没有分析时出现一条消息来告知原因。
该在什么情况下静默失败呢?
如果用户只想看到结果,并不知道要分析那些文件,可能就无须在有些文件不存在时告知他们。向用户显示他不想看到的信息可能会降低程序的可用性。Python 的错误处理结构让你能够细致地控制与用户分享错误信息,要分享多少信息由你决定。
编写得很好且经过详尽测试的代码不容易出现内部错误,如语法或逻辑错误,但只要程序依
赖于外部因素,如用户输人、存在指定的文件、有网络链接,就有可能出现异常。凭借经验可判
该在程序的什么地方包含异常处理块。以及出现错误时,该向用户提供多少相关的信息。