python try except
在本教程中,我们将学习有关使用try..except块处理Python编程中的错误和异常的所有信息。
Python内置异常
在开始使用try..except块之前,让我们看一下Python的一些内置异常。
Python附带了许多内置的异常类,以涵盖许多错误情况,因此我们不必定义自己的异常类。这些类分为"基本"错误类(从中定义其他错误类)和"具体"错误类,这些类定义了我们更可能不时看到的异常。
以下是一些常见的错误和异常类:
SyntaxError:
,当我们输入一行代码,Python解释器无法解析时,会发生此错误ImportError:
当无法解析导入时发生。KeyError:
,当尝试访问它时找不到字典键时会发生TypeError:
,如果我们尝试对错误类型的值或者对象执行操作,则会发生AttributeError
:当分配或者引用属性失败时引发。IndexError:
如果我们尝试访问不存在的索引(例如,列表中的索引),则会发生此错误。NameError:
当在本地或者全局找不到指定名称时发生FileNotFoundError:
如果找不到试图读取或者写入的文件,则会引发此错误
处理错误和异常
Python使用称为异常的特殊对象来管理程序执行期间发生的错误。每当发生使Python不确定下一步该做什么的错误时,它都会创建一个异常对象。如果我们编写处理该异常的代码,该程序将继续运行。如果我们不处理该异常,则该程序将停止并显示回溯,其中包括所引发异常的报告。
不同的try语句子句
当我们编写try
语句时,在try标头之后可能会出现各种子句。下面总结了我们将在本教程中介绍的所有可能的形式。
条款格式 | 解释 |
---|---|
except:Catch all (or all other) exception types. except name: | 仅捕获特定的异常。 |
except name as value: | 捕获列出的异常并分配其实例。 |
except(name1,name2): | except(name1,name2): |
except(name1,name2)as value: | 捕获任何列出的异常并分配其实例。 |
else: | 如果try块中没有引发异常,则运行。 |
finally: | 总是在退出时执行此阻塞。 |
try..except块
异常通过try-except块进行处理。一个try-except块要求Python做某事,但是它也告诉Python如果引发异常该怎么办。当我们使用try-except块时,即使事情开始出错,程序也将继续运行。用户可以看到我们编写的友好错误消息,而不会引起用户阅读混乱,而回溯。
语法
使用try..except
块的基本语法是:
try: # do something here except [Exception]: # If there is Exception, then execute this block.
我们可以定义多个异常块来处理不同种类的异常。我们将使用不同的示例进行介绍,以更好地理解。
示例1:处理单个异常
在处理异常之前,让我向我们展示一个一般情况,其中脚本在尝试打开文件时可能失败,但该文件不存在。在这种情况下,我们将得到FileNotFoundError
异常,最糟糕的部分是此异常之后的任何代码都不会执行
#!/usr/bin/env python3 with open('input.txt', 'r') as myfile: for line in myfile: print(line) print('Outside the with block')
如预期的那样,我们将收到FileNotFoundError
异常。因此,我们将使用try..except
块来处理此问题:
#!/usr/bin/env python3 try: with open('input.txt', 'r') as myfile: for line in myfile: print(line) except: print('Sorry, file doesn\'t exist') print('Outside the with block')
我已经更新了代码,尽管我没有定义异常的类型,并且使用了通用的除外块,所以对于任何类型的错误,我都会得到"抱歉,文件不存在"。
所以现在我们没有任何异常,并且在with块之外的print语句也被执行了。
示例2:提供异常类型
如前所述,在上一个示例中,我没有定义异常的类型,因此对于任何类型的问题,我都会得到相同的消息,这可能会引起误解。例如,文件存在,尽管用户没有足够的权限访问该文件,但我仍然会收到相同的消息。
为了演示,我使用普通用户执行相同的脚本。我已经以root用户身份创建了input.txt,并且仅授予了600
的权限,因此用户'hynman'没有读取该文件的权限
[hynman@server ~]$ls -l input.txt -rw------- 1 root root 0 Oct 15 14:49 input.txt
现在,我执行示例1中的相同脚本:
[hynman@server ~]$python3 handle-exceptions.py Sorry, file doesn't exist Outside the with block
很抱歉,我们仍然会收到"抱歉,文件不存在",因为该文件实际上在那儿,但是我没有访问该文件的权限。
为了处理这种情况,我们可以使用except块定义Exception Type
:
#!/usr/bin/env python3 try: with open('input.txt', 'r') as myfile: for line in myfile: print(line) except FileNotFoundError: print('Sorry, file doesn\'t exist') except PermissionError: print('Sorry, you don\'t have permission to access the file') print('Outside the with block')
因此,现在我增强了脚本的处理能力,使其可以处理两个单独的FileNotFoundError和PermissionError异常。
示例3:在单个块中定义多个异常
在前面的示例中,我们为单个异常定义了单独的块。我们还可以将所有适用的异常合并在单个" except"块中。例如,我将FileNotFoundError
和PermissionError
合并为单个除外块,并给出了更精确的print
语句:
#!/usr/bin/env python3 try: with open('input.txt', 'r') as myfile: for line in myfile: print(line) except (FileNotFoundError, PermissionError): print('Sorry, file doesn\'t exist or you don\'t have permission to access the file') print('Outside the with block')
因此,使用这种方法可以节省几行代码。
示例4:使用通用异常块
现在,我们介绍了一些手动定义异常类型的场景,但是也有可能异常类型与我们在代码中添加的异常类型不匹配,在这种情况下,最好还是添加'Exception'除外以处理无法预料的问题。另外,我们可以将输出存储到变量中,然后将该变量打印为输出。
我已经用except Exception
块更新了脚本,以处理代码中未定义的任何其他异常并将输出存储到error
变量中,稍后我将打印该变量的内容:
#!/usr/bin/env python3 try: with open('input.txt', 'r') as myfile: for line in myfile: print(line) except FileNotFoundError: print('Sorry, file doesn\'t exist or you don\'t have permission to access the file') except Exception as error: print(error) print(type(error)) print('Outside the with block')
try..except..else块
" try ... except ... else"块是对传统" try ... except"块的较小修改,因此它可以包含" else"块。
语法
try..except..else块的语法为:
try: # do something here except [Exception]: # If there is Exception, then execute this block. else: # If there are no exceptions then execute this block
如果未发生任何错误,则"总是"执行" else"块中的代码。因此,任何依赖于成功执行的try块的代码都将进入else块:
示例:对try块使用try
在此示例脚本中,我们将提示用户输入两个数字,并使用python代码将第一个数字除以第二个数字
该脚本的输出:
~]$python3 handle-exceptions.py Give me two numbers Enter 'q' to quit First number: 10 Second number: 5 You get: 2.0 First number: 10 Second number: 0 Traceback (most recent call last): File "handle-exceptions.py", line 13, in answer = int(first_num)/int(second_num) ZeroDivisionError: division by zero
因此,如果我们尝试将"第一个数字"除以0,则会得到" ZeroDivisionError"异常。让我尝试使用except和else块来处理" ZeroDivisionError":
#!/usr/bin/env python3 print("Give me two numbers") print("Enter 'q' to quit") while True: first_num = input("\nFirst number: ") if first_num == 'q': break second_num = input("Second number: ") if second_num == 'q': break try: answer = int(first_num)/int(second_num) except ZeroDivisionError: print("You can not divide by 0") else: print('You get: ', answer)
该脚本的输出:
因此,现在对所有SUCCESS条件执行else
块,而except块将处理ZeroDivisionError
异常。
try..finally 块
当我们想传播异常但又希望运行清除代码(即使发生异常)时,我们可以使用" try..finally"。 try..finally的一种常见用法是可靠关闭文件句柄
语法
使用try..except..finally
块的语法是。 except块是可选的,我们也可以不带except
块而使用try..finally
。
try: # do something here except [Exception]: # If there is Exception, then execute this block. finally: # This is executed always
如果我们希望结合使用" else"块,则语句的顺序应为:
try -> except -> else -> finally
例1:使用try finally
我将举一个简单的示例来了解try..finally
块的用法。其中我们将提示用户输入带有整数的输入,接下来,我们将100除以该数字并将结果存储在re
中。
现在,如果引发了异常,那么我们进入
except
块如果没有异常,则执行" else"块
不论异常如何,都将始终执行
finally
块
#!/usr/bin/env python3 try: num = int(input("Enter the number: ")) re = 100/num except: print("Something is wrong") else: print("result is ",re) finally : print("finally program ends") print('END')
此脚本的输出(无例外):
~]$python3 try-finally.py Enter the number: 10 result is 10.0 finally program ends END
该脚本的输出(例外):
~]$python3 try-finally.py Enter the number: abcd Something is wrong finally program ends END
因此,在两种情况下,都执行了" finally"块。
示例2:使用try..finally块打开和关闭文件句柄
这是一个更实际的示例,其中我们打开一个文件来执行一些读写操作,并且有意地尝试写入无效的utf-8内容,这将引发UnicodeDecodeError,在这种情况下,finally块将执行并关闭文件句柄。
说明:
我们必须在try块之前调用open,因为打开文件时发生的异常(例如OSError,如果文件不存在)应完全跳过finally块:
该脚本的输出:
~]$python3 try-finally.py * Opening file * Reading data * Calling close() Traceback (most recent call last): File "try-finally.py", line 11, in handle.read() # Maybe UnicodeDecodeError File "/usr/lib64/python3.6/codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte
因此,即使我们收到了异常,我们也执行了来自" finally"块的代码以关闭文件句柄。
手动引发异常
要显式地触发异常,可以编写raise
语句。它们的一般形式很简单-一个raise语句由单词单词引发,可以选择跟在要引发的类或者其实例之后:
语法:
raise instance # Raise instance of class raise class # Make and raise instance of class: makes an instance raise # Reraise the most recent exception
例如,这里有一个简单的if else条件。
如果条件匹配,那么我们将在控制台上打印一些内容;否则,我们将使用一些自定义消息引发ValueError:
#!/usr/bin/env python3 num = int(input('Enter any number: ')) mylist = [10, 21, 34, 49, 52] if num in mylist: print('Bingo, you hit the Hymanpot') else: raise ValueError('Ohh, you missed the Hymanpot')
该脚本的输出:
~]$python3 raise-exceptions-1.py Enter any number: 20 Traceback (most recent call last): File "raise-exceptions-1.py", line 9, in raise ValueError('Ohh, you missed the Hymanpot') ValueError: Ohh, you missed the Hymanpot
如我们所见,由于提供的号码不是mylist的一部分,因此ValueError如我们所定义的那样引发。因此,使用raise,我们可以在python代码中手动创建异常。
定义并引发自定义异常
内置异常涵盖了多种情况。但是,有时我们可能需要定义一个自定义异常以适合特定应用程序情况。例如," MyCustomError"异常。
在这种情况下,Python包含通过扩展基本Exception类来添加自定义错误的功能。我们将使用现有示例,而不是ValueError
,我们将创建自己的异常并在else块中执行它:
当我们提供列表中不存在的数字时,此脚本的输出:
~]$python3 raise-exceptions-1.py Enter any number: 20 Traceback (most recent call last): File "raise-exceptions-1.py", line 12, in raise MyCustomError('Ohh, you missed the Hymanpot') __main__.MyCustomError: Ohh, you missed the Hymanpot
断言
Python包含assert
语句。创建真实测试的下一步是断言特定的比较正确。断言通常用于在开发过程中验证程序条件。例如,其中我使用assert来执行比较,而不是if条件,如果条件不匹配,则引发异常
#!/usr/bin/env python3 class MyCustomError(Exception): pass num = int(input('Enter any number: ')) mylist = [10, 21, 34, 49, 52] try: assert num in mylist print('Bingo, you hit the Hymanpot') except: print('Ohh, you missed the Hymanpot')
该脚本的输出:
~]$python3 raise-exceptions-1.py Enter any number: 20 Ohh, you missed the Hymanpot
由于" assert"条件不匹配,因此执行了except块。