使用 Python 编码时,即使是在语法和逻辑上正确的程序中,您也经常会出现运行时错误。这些错误可能是由无效输入或某些前后矛盾引起的。在 很多语言中都提供了异常处理机制,在Python 中,您可以使用try和except块来更优雅地将大多数这些错误作为异常处理。在本教程中,您将学习的一般语法try和except。然后我们将继续编写简单的示例,讨论可能出错的地方,并使用try和except块提供纠正措施。
Python try 和 except 块的语法
让我们从了解Python 中try和except语句的语法开始介绍。通用模板如下图所示:
try:
# There can be errors in this block
except <error type>:
# Do this to handle exception;
# executed if the try block throws an error
else:
# Do this if try block executes successfully without errors
finally:
# This block is always executed
让我们看看不同块的用途:
- 该try代码块是你想尝试执行的语句块。但是,由于异常可能会出现运行时错误,所以此块可能无法按预期工作。
- 该except代码块是触发try块时需要执行的语句。它包含一组语句,这些语句通常会为您提供有关try块内出错的一些处理方法。
- 您应该始终提及您打算在代码块内作为异常捕获的错误类型,由上述代码段中的占位符表示。例如:except<error type>
- 您也可以不在except指定<error type>. 但是,这不是推荐的做法,因为您没有考虑可能发生的不同类型的错误。
在尝试执行try块内的代码时,也有可能发生多个错误。
例如,您可能正在使用超出范围的索引访问列表,使用错误的字典键,并尝试打开一个不存在的文件 - 所有这些都应该放在try块内。
在这种情况下,你可能会碰到IndexError
,KeyError
和FileNotFoundError
。并且您必须添加与except您预期的错误数量一样多的每种类型的错误一个。
仅当try块在没有错误的情况下执行时,才会触发else块。当您希望在try块成功后执行后续操作时,这可能非常有用。例如,如果您尝试成功打开一个文件,则可能需要读取其内容。
- 该finally块总是被执行,而不管其他块中发生了什么。当您想在执行特定代码块后释放资源时,这很有用。
注意:else和finally块是可选的。在大多数情况下,您可以只使用try块来尝试做某事,并将错误捕获为except块内的异常。
在接下来的几分钟内,您将使用迄今为止学到的知识来处理 Python 中的异常。让我们开始吧。
如何处理Python中的ZeroDivision(除零异常)错误
考虑下面所示的函数divide()。它接受两个参数 num和div ,并返回除法运算的商num/div。
def divide(num,div):
return num/div
▶ 使用不同的参数调用函数会按预期返回结果:
res = divide(100,8)
print(res)
# Output
12.5
res = divide(568,64)
print(res)
# Output
8.875
此代码工作正常,直到您尝试除以零:
divide(27,0)
您会看到程序崩溃并抛出ZeroDivisionError:
# Output
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-19-932ea024ce43> in <module>()
----> 1 divide(27,0)
<ipython-input-1-c98670fd7a12> in divide(num, div)
1 def divide(num,div):
----> 2 return num/div
ZeroDivisionError: division by zero
您可以通过执行以下操作将此除以零作为异常处理:
- 在try块中,调用divide()函数。从本质上讲,您正在试图将num除以div。
- 当div为0的情况作为except块内的异常处理。
- 在此示例中,您可以通过打印一条消息来通知用户他们尝试除以零,从而排除
ZeroDivisionError
异常。
这显示在下面的代码片段中:
try:
res = divide(num,div)
print(res)
except ZeroDivisionError:
print("You tried to divide by zero :( ")
使用有效的输入,代码仍然可以正常工作。
divide(10,2)
# Output
5.0
当您尝试除零时,您会收到发生异常的通知,并且程序会正常结束。
divide(10,0)
# Output
You tried to divide by zero :(
如何在 Python 中处理 TypeError(类型异常)
在本节中,您将看到如何在 Python 中使用try和except处理一个 TypeError。
▶ 考虑以下函数add_10(),它接受一个数字作为参数,将其加 10,然后返回加法的结果。
def add_10(num):
return num + 10
您可以使用任意数字参数调用该函数,它会正常工作,如下所示:
result = add_10(89)
print(result)
#Output
99
现在尝试add_10()使用"five"而不是调用5。
add_10("five")
您会注意到您的程序崩溃并显示以下错误消息:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-9844e949c84e> in <module>()
----> 1 add_10("five")
<ipython-input-13-2e506d74d919> in add_10(num)
1 def add_10(num):
----> 2 return num + 10
TypeError: can only concatenate str (not "int") to str
该错误消息TypeError: can only concatenate str (not "int") to str
说明您只能连接两个字符串,而不能向字符串添加整数。
现在,您有以下内容:
- 给定一个数字my_num,尝试使用my_num作为参数调用函数add_10()。如果参数是有效类型,则不存在异常
- 否则,将触发与TypeError对应的except块,通知用户参数的类型无效。
这一点解释如下:
my_num = "five"
try:
result = add_10(my_num)
print(result)
except TypeError:
print("The argument `num` should be a number")
由于您现在已将TypeError
作为异常处理,因此您只会被告知参数的类型无效。
The argument `num` should be a number
如何在 Python 中处理 IndexError(无效索引)
如果您之前使用过 Python 列表或任何可迭代的 Python数据类型,您可能会遇到IndexError
.
这是因为通常很难跟踪可迭代对象的所有更改。并且您可能正在尝试访问无效索引处的项。
▶ 在这个例子中,列表my_list有 4 个项。如果使用负索引,则有效索引为 0、1、2 和 3,以及 -1、-2、-3、-4。
由于2是有效的索引,您可以看到索引2中的项被打印出来,即C++:
my_list = ["Python","C","C++","JavaScript"]
print(my_list[2])
#Output
C++
如果您尝试访问位于有效索引范围之外的索引处的项,您将遇到IndexError
:
print(my_list[4])
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-7-437bc6501dea> in <module>()
1 my_list = ["Python","C","C++","JavaScript"]
----> 2 print(my_list[4])
IndexError: list index out of range
如果您熟悉该模式,您现在将使用try和except来处理索引错误。
▶ 在下面的代码片段中,您尝试访问由 指定的索引处的项目search_idx。
search_idx = 3
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
这里,search_idx( 3) 是一个有效的索引,并且打印出特定索引处的项目:
JavaScript
如果search_idx超出索引的有效范围,则 except 块将 捕获IndexError为异常,并且不再有错误消息。
search_idx = 4
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
而是显示search_idx超出有效索引范围的消息:
Sorry, the list index is out of range
如何在 Python 中处理 KeyError(键值对异常)
在使用 Python 词典时可能遇到过KeyError。
▶ 考虑这个例子,你有一本字典my_dict。
my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
search_key = "non-existent key"
print(my_dict[search_key])
- 字典my_dict有 3 个键值对,"key1:value1", "key2:value2", 和"key3:value3"
- 现在,您尝试访问字典并访问与 key 对应的值"non-existent key"。
正如预期的那样,你会得到一个KeyError:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-2-2a61d404be04> in <module>()
1 my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
2 search_key = "non-existent key"
----> 3 my_dict[search_key]
KeyError: 'non-existent key'
几乎可以像处理IndexError一样处理KeyError.
- 您可以尝试访问与指定的键对应的值search_key。
- 如果search_key确实是一个有效的键,则打印出相应的值。
- 如果由于密钥不存在而遇到异常,您可以使用该except块让用户知道。
这在下面的代码片段中进行了解释:
try:
print(my_dict[search_key])
except KeyError:
print("Sorry, that's not a valid key!")
Sorry, that's not a valid key!
▶ 如果您想提供其他操作,例如无效密钥的名称,您也可以这样做:密钥可能拼写错误,使其无效。在这种情况下,让用户知道使用的密钥可能会帮助他们修复拼写错误。
您可以通过捕获无效密钥<error_msg>并在发生异常时打印的消息中使用它来实现此目的:
try:
print(my_dict[search_key])
except KeyError as error_msg:
print(f"Sorry,{error_msg} is not a valid key!")
▶ 注意键名也是如何打印出来的:
Sorry,'non-existent key' is not a valid key!
如何在 Python 中处理 FileNotFoundError(文件找不到异常)
在 Python 中处理文件时发生的另一个常见错误是FileNotFoundError.
▶ 在以下示例中,您尝试通过指定open()函数的路径来打开文件my_file.txt。并且您想读取该文件并打印出该文件的内容。
但是,您尚未在指定位置创建文件。
如果您尝试运行下面的代码片段,您将得到FileNotFoundError:
my_file = open("/content/sample_data/my_file.txt")
contents = my_file.read()
print(contents)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-4-4873cac1b11a> in <module>()
----> 1 my_file = open("my_file.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'my_file.txt'
并使用try和 except,您可以执行以下操作:
- 尝试在try块中打开文件。
- 处理FileNotFoundError:通过except让用户知道他们试图打开一个不存在的文件块。
- 如果try块成功,并且文件确实存在,则读取并打印出文件的内容。
- 在finally块中,关闭文件,以免浪费资源。回想一下文件将如何关闭,而不管文件打开和读取步骤中发生了什么。
try:
my_file = open("/content/sample_data/my_file.txt")
except FileNotFoundError:
print(f"Sorry, the file does not exist")
else:
contents = my_file.read()
print(contents)
finally:
my_file.close()
请注意您是如何将错误作为异常处理的,程序结束时会优雅地显示以下消息:
Sorry, the file does not exist
▶ 让我们考虑else触发块的情况。该文件my_file.txt现在位于前面提到的路径中。
这是文件my_file.txt包含的内容:
现在,重新运行之前的代码片段按预期工作。
这一次,文件my_file.txt存在,else块被触发并打印出其内容,如下所示:
我希望这能阐明您在处理文件时如何处理异常。