网站首页> 文章专栏> 机器学习之Python(12): Python中try - except
机器学习之Python(12): Python中try - except
原创 时间:2025-03-28 15:21 作者:管理员 浏览量:53

在 Python 中,我们可以使用try - except语句来优雅地处理这些异常情况,让程序更加健壮和稳定。它就像是给程序穿上了一层 “防护服”,当遇到异常时,能够及时进行 “修复”,避免程序的崩溃。接下来,就让我们深入了解一下try - except的用法。

一、Python 异常那些事儿

(一)异常是什么

在深入了解try - except之前,我们先来认识一下异常。在 Python 中,异常是指程序在运行时出现的错误或意外情况。它与语法错误不同,语法错误是在代码编写阶段就会被发现的,比如少了一个冒号、括号不匹配等,这些错误会导致代码无法正常运行,Python 解释器会直接提示语法错误信息,并且不会执行代码。而异常是在代码语法正确的前提下,在运行过程中出现的错误。例如:
num = 10 / 0
这段代码的语法是正确的,但是在运行时会出现ZeroDivisionError异常,因为在数学运算中,除数不能为 0。异常的出现会导致程序中断执行,如果不进行处理,程序就会崩溃并显示错误信息,这对于一个健壮的程序来说是不可接受的。

(二)常见异常类型列举

Python 中有许多不同类型的异常,每种异常都代表着不同的错误情况 。下面为大家列举一些常见的异常类型:
  • ZeroDivisionError:除(或取模)零异常。就像上面提到的num = 10 / 0,当进行除法运算时,除数为 0 就会触发这个异常。
  • IndexError:索引超出范围异常。比如:
lst = [1, 2, 3]
print(lst[3])
这里列表lst只有 3 个元素,索引范围是 0 到 2,当尝试访问索引为 3 的元素时,就会引发IndexError异常。
  • KeyError:字典中查找一个不存在的键时触发的异常。示例如下:
d = {'a': 1, 'b': 2}
print(d['c'])
字典d中只有键'a'和'b',当查找键'c'时,就会出现KeyError异常。
  • NameError:尝试访问一个不存在的变量时会触发此异常。例如:
print(nonexistent_var)
这里nonexistent_var变量没有被定义,运行时就会抛出NameError异常。
  • TypeError:不同类型间的无效操作异常。比如:
print(1 + "2")
整数和字符串不能直接相加,这种类型不匹配的操作会导致TypeError异常。

二、try - except 基础语法详解

(一)try 块

try块用于包裹可能出现异常的代码。当程序执行到try块时,会尝试执行其中的代码。如果在执行过程中没有发生异常,那么程序会跳过except块,继续执行try - except语句之后的代码。例如:
try:
num = 10 + 5
print(num)
except:
print("发生异常")
在这个例子中,try块中的代码num = 10 + 5和print(num)不会引发异常,所以except块不会被执行,程序会正常输出结果15 。

(二)except 块

except块用于捕获并处理try块中发生的异常。它有多种使用方式,下面为大家详细介绍:
  1. 捕获特定类型异常:可以指定except捕获特定类型的异常。当try块中引发的异常类型与except指定的异常类型相匹配时,就会执行该except块中的代码。例如:
try:
result = 10 / 0
except ZeroDivisionError:
print("除数不能为零")
在这个例子中,try块中的10 / 0会引发ZeroDivisionError异常,由于except指定了捕获ZeroDivisionError异常,所以会执行except块中的代码,输出 “除数不能为零” 。
2. 捕获所有异常:使用except语句不带任何异常类型,或者使用except Exception as e可以捕获所有类型的异常。其中,Exception是所有内置异常的基类 。e是异常对象,可以通过它获取异常的相关信息。例如:
try:
num = int("abc")
result = 10 / num
except Exception as e:
print(f"发生异常: {e}")
在这个例子中,try块中的int("abc")会引发ValueError异常,因为无法将字符串"abc"转换为整数。由于使用了except Exception as e,所以可以捕获到这个异常,并输出异常信息,如 “发生异常: invalid literal for int () with base 10: 'abc'” 。不过,这种捕获所有异常的方式要谨慎使用,因为它可能会掩盖一些潜在的问题,不利于调试和定位错误。
3. 多 except 块:一个try块可以对应多个except块,用于捕获不同类型的异常,并进行相应的处理。当try块中发生异常时,Python 会按照except块的顺序依次匹配异常类型,一旦找到匹配的except块,就会执行该块中的代码,不再继续匹配后面的except块。例如:
try:
num = input("请输入一个数字: ")
num = int(num)
result = 10 / num
print(f"结果是: {result}")
except ValueError:
print("输入的不是有效的数字")
except ZeroDivisionError:
print("除数不能为零")
在这个例子中,首先尝试将用户输入转换为整数,如果输入不是有效的数字,会引发ValueError异常,此时会执行第一个except块中的代码,提示用户输入的不是有效的数字;如果输入是有效的数字,但为 0,会引发ZeroDivisionError异常,此时会执行第二个except块中的代码,提示除数不能为零 。通过使用多个except块,可以使程序对不同类型的异常进行更细致的处理,提高程序的健壮性和用户体验。

三、try - except 进阶用法

(一)else 语句

在try - except结构中,还可以使用else语句。else块中的代码只有在try块中没有发生异常时才会执行。它为我们提供了一种将正常执行的代码与异常处理代码分离的方式,使代码结构更加清晰。其语法结构如下:
try:
# 可能会抛出异常的代码
pass
except SomeExceptionType:
# 当try块中抛出SomeExceptionType类型的异常时执行的代码
pass
else:
# 当try块中的代码没有抛出异常时执行的代码
pass
例如,在文件读取操作中,我们可以这样使用else语句:
try:
file_name = "example.txt"
with open(file_name, 'r') as file:
content = file.read()
except FileNotFoundError:
print(f"文件{file_name}不存在")
else:
print(f"文件内容为:\n{content}")
在这个例子中,如果文件example.txt存在,try块中的代码会正常读取文件内容,由于没有发生异常,程序会接着执行else块中的代码,打印文件内容。如果文件不存在,try块会抛出FileNotFoundError异常,程序会跳转到except块,打印文件不存在的提示信息,此时else块不会被执行 。通过这种方式,将文件读取成功后的处理逻辑放在else块中,与异常处理代码分开,提高了代码的可读性和可维护性。

(二)finally 语句

finally语句用于定义无论是否发生异常都要执行的代码块,通常用于资源清理操作,比如关闭文件、释放数据库连接等。它的语法结构如下:
try:
# 可能会抛出异常的代码
pass
except SomeExceptionType:
# 当try块中抛出SomeExceptionType类型的异常时执行的代码
pass
finally:
# 无论是否发生异常都会执行的代码
pass
例如,在文件操作中,无论文件读取是否成功,都需要关闭文件,以释放系统资源。可以使用finally语句来实现:
file = None
try:
file = open("test.txt", "r")
content = file.read()
print(content)
except FileNotFoundError:
print("文件不存在")
finally:
if file:
file.close()
在这个例子中,try块尝试打开并读取文件,如果文件不存在,会捕获FileNotFoundError异常并打印提示信息。无论是否发生异常,最终都会执行finally块中的代码,关闭文件。即使在try块或except块中使用了return语句,finally块中的代码仍然会执行 。比如:
def read_file():
file = None
try:
file = open("test.txt", "r")
content = file.read()
return content
except FileNotFoundError:
print("文件不存在")
finally:
if file:
file.close()
result = read_file()
print(result)
在这个函数中,try块读取文件内容后使用return返回内容,但在返回之前,finally块中的代码会先执行,关闭文件。
再比如在数据库连接操作中,使用pymysql库连接 MySQL 数据库时,无论数据库操作是否成功,都需要关闭数据库连接以释放资源。示例如下:
import pymysql
def query_database():
connection = None
try:
connection = pymysql.connect(host='localhost',
user='your_username',
password='your_password',
database='your_database',
port=3306,
charset='utf8mb4')
cursor = connection.cursor()
sql = "SELECT * FROM your_table"
cursor.execute(sql)
results = cursor.fetchall()
for row in results:
print(row)
except pymysql.Error as e:
print(f"发生错误:{e}")
finally:
if connection:
connection.close()
query_database()
在这个示例中,try块用于执行数据库查询操作,如果发生错误,except块捕获并处理异常。无论是否发生异常,finally块中的代码都会执行,关闭数据库连接,确保资源得到正确释放,避免资源泄漏等问题,提高程序的稳定性和可靠性。

四、try - except 实际应用场景

(一)文件操作

在进行文件操作时,经常会遇到各种异常情况,如文件不存在、权限不足等。使用try - except可以有效地处理这些异常,保证程序的稳定性。例如,在读取文件时:
try:
with open('test.txt', 'r') as file:
content = file.read()
print(content)
except FileNotFoundError:
print("文件不存在")
except PermissionError:
print("权限不足,无法读取文件")
在这个例子中,try块尝试打开并读取test.txt文件。如果文件不存在,会引发FileNotFoundError异常,except块会捕获该异常并打印 “文件不存在”;如果没有读取文件的权限,会引发PermissionError异常,except块会捕获并打印 “权限不足,无法读取文件” 。
再比如,在写入文件时:
try:
with open('output.txt', 'w') as file:
file.write("这是写入的内容")
except PermissionError:
print("权限不足,无法写入文件")
except Exception as e:
print(f"写入文件时发生错误: {e}")
这里try块尝试打开output.txt文件并写入内容。如果没有写入权限,会捕获PermissionError异常;如果发生其他异常,会捕获Exception异常,并打印错误信息,通过这种方式,使文件操作更加健壮,避免因异常导致程序崩溃 。

(二)网络请求

在进行网络请求时,由于网络环境的不确定性,可能会出现各种异常,如请求超时、HTTP 错误、连接错误等。以使用requests库发送 HTTP 请求为例,来看如何处理这些异常:
import requests
try:
response = requests.get('https://example.com', timeout=5)
response.raise_for_status() # 检查HTTP状态码,如果不是200,会引发HTTPError异常
print(response.text)
except requests.Timeout:
print("请求超时")
except requests.HTTPError as e:
print(f"HTTP错误: {e}")
except requests.ConnectionError:
print("连接错误")
except requests.RequestException as e:
print(f"请求发生异常: {e}")
在这个例子中,try块使用requests.get方法发送 HTTP 请求,并设置超时时间为 5 秒。如果请求超时,会引发requests.Timeout异常,except块捕获并打印 “请求超时”;response.raise_for_status()用于检查 HTTP 状态码,如果状态码不是 200(如 404、500 等),会引发requests.HTTPError异常,except块捕获并打印 HTTP 错误信息;如果发生连接错误,会引发requests.ConnectionError异常,except块捕获并打印 “连接错误”;requests.RequestException是requests库中所有异常的基类,如果发生其他与请求相关的异常,会捕获requests.RequestException异常,并打印异常信息 。通过这样的异常处理机制,可以使网络请求更加可靠,即使遇到异常情况,也能给用户提供友好的提示,而不是让程序直接崩溃。

(三)用户输入验证

在获取用户输入时,用户可能会输入不符合预期的数据,从而导致程序出现异常。使用try - except可以捕获这些异常,进行相应的处理。例如,要求用户输入一个整数,然后进行除法运算:
try:
num = input("请输入一个整数: ")
num = int(num)
result = 10 / num
print(f"结果是: {result}")
except ValueError:
print("输入的不是有效的整数")
except ZeroDivisionError:
print("除数不能为零")
在这个例子中,try块首先获取用户输入,并尝试将其转换为整数。如果用户输入的不是有效的整数,会引发ValueError异常,except块捕获并打印 “输入的不是有效的整数”;如果用户输入的整数为 0,在进行除法运算时会引发ZeroDivisionError异常,except块捕获并打印 “除数不能为零” 。通过这种方式,可以对用户输入进行有效的验证和处理,提高程序的健壮性和用户体验。

(四)数据库操作

在进行数据库操作时,也可能会遇到各种异常,如连接失败、SQL 语法错误等。以使用pymysql库连接 MySQL 数据库为例,来看如何处理这些异常:
import pymysql
try:
connection = pymysql.connect(host='localhost',
user='your_username',
password='your_password',
database='your_database',
port=3306,
charset='utf8mb4')
cursor = connection.cursor()
sql = "SELECT * FROM your_table"
cursor.execute(sql)
results = cursor.fetchall()
for row in results:
print(row)
except pymysql.Error as e:
print(f"数据库操作发生错误: {e}")
finally:
if connection:
connection.close()
在这个例子中,try块尝试连接 MySQL 数据库,并执行 SQL 查询语句。如果连接数据库失败或执行 SQL 语句时发生错误,会引发pymysql.Error异常,except块捕获并打印错误信息;无论是否发生异常,finally块中的代码都会执行,关闭数据库连接,释放资源,确保程序的稳定性和资源的正确管理 。

五、异常处理的注意事项

(一)避免过度捕获异常

在使用try - except时,要注意避免过度捕获异常。虽然使用except Exception或except(不带异常类型)可以捕获所有异常,但这可能会隐藏真正的错误,给调试和定位问题带来困难。例如:
try:
result = 10 / int(input("请输入一个数字: "))
print(f"结果是: {result}")
except:
print("出现了一些问题")
在这个例子中,无论输入是什么导致的异常,都会被捕获并打印 “出现了一些问题”。这使得我们无法得知具体是输入不是数字引发的ValueError,还是输入为 0 引发的ZeroDivisionError等。如果在后续维护中,需要根据不同的异常进行不同的处理,这种宽泛的异常捕获方式就会带来很大的麻烦。所以,应尽量精确地捕获特定类型的异常,这样可以更有针对性地处理问题,同时也方便调试和维护。

(二)合理使用异常处理

不要用异常处理替代正常的逻辑判断。异常处理机制的设计初衷是处理程序运行时出现的意外情况,而不是用于替代常规的条件判断逻辑。因为异常处理的开销相对较大,频繁地使用异常处理会影响程序的性能。例如,在检查一个文件是否存在时,有两种方式:
方式一:使用正常的逻辑判断
import os
file_name = "test.txt"
if os.path.exists(file_name):
with open(file_name, 'r') as file:
content = file.read()
print(content)
else:
print(f"文件{file_name}不存在")
方式二:使用异常处理
try:
with open("test.txt", 'r') as file:
content = file.read()
print(content)
except FileNotFoundError:
print("文件不存在")

在这个场景中,使用os.path.exists进行文件是否存在的判断是更合适的做法,它的逻辑清晰,性能也更好。而使用异常处理虽然也能达到目的,但在文件存在的正常情况下,异常处理的开销是不必要的。只有当我们无法预先判断某个操作是否会出现异常,或者异常情况确实是不可预见的意外时,才应该使用异常处理机制 。比如在进行网络请求时,由于网络的不确定性,我们很难提前判断请求是否会成功,这时使用异常处理来捕获可能出现的异常就是合理的。


动动小手 !!!
来说两句吧
最新评论