python try except

时间:2020-02-23 14:43:37  来源:igfitidea点击:

在本教程中,我们将学习有关使用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"块中。例如,我将FileNotFoundErrorPermissionError合并为单个除外块,并给出了更精确的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块。