Python异常处理详解

在编程的世界里,错误和异常是不可避免的。它们是编程生涯中不可或缺的一部分,也是提升编程能力的重要途径。面对bug和错误,不仅要解决它们,更要从中学习,这样才能成为更优秀的程序员。在任何编程语言中,编写程序时都有一定的规则,比如在定义变量名时不能使用空格,if语句后必须加上冒号等。如果不遵守这些规则,就会遇到语法错误,程序也会因此拒绝执行,直到修正这些错误。

然而,有时候即使程序在语法上是正确的,执行时仍然会抛出错误,这些在执行过程中被检测到的错误被称为异常。处理这些异常的过程就叫做异常处理。在Python中,异常处理是一个非常重要的概念,它可以帮助优雅地处理程序运行中可能出现的错误,防止程序崩溃。

Python异常处理的优势

为什么要学习异常处理呢?这里有两个主要的理由。首先,假设编写了一个脚本来读取多个目录中成千上万的文件,可能会遇到文件类型缺失、格式错误或不同扩展名等问题。在这种情况下,不可能打开所有文件并为每种情况编写相应的脚本。异常处理允许定义多种条件,例如,如果格式错误,可以先纠正格式,然后再尝试读取文件;否则,跳过该文件,并创建一个日志文件,以便稍后处理。

其次,假设正在从网站抓取餐厅数据,脚本寻找餐厅的名称、评论和地址。由于某些原因,网站上缺少餐厅的地址。在这种情况下,如果不处理异常,脚本可能会在中途停止。因此,在收集大量数据时,处理异常是至关重要的。

Python中的常见异常

以下是在Python中可能会遇到的一些常见异常:

  • ZeroDivisionError:当尝试将一个数字除以零时会引发此异常。
  • ImportError:当尝试导入未安装的库或提供了错误名称时会引发此异常。
  • IndexError:在序列中找不到索引时会引发此异常。例如,如果列表的长度是10,而尝试访问第11个索引,就会得到这个错误。
  • IndentationError:当缩进没有正确指定时会引发此异常。
  • ValueError:当内置函数的数据类型有有效的参数类型,但参数值无效时会引发此异常。
  • Exception:所有异常的基类。如果不确定可能发生哪种异常,可以使用基类。它将处理所有异常。

可以在这里阅读更多关于常见异常的信息。

Python中的try-except语句

在像Python这样的编程语言中,try()函数用于处理可能在代码块执行期间发生的异常或错误。它允许优雅地捕获和处理异常,防止程序崩溃。

try()的工作原理如下:

  1. 将代码块封装在try语句中。
  2. try块中的代码将按顺序执行。
  3. 如果在try块中发生异常,程序将跳转到最近的except块。
  4. except块处理异常并执行适当的操作,如记录错误消息或采取纠正措施。
  5. 执行完except块后,程序将运行try-except结构之外的后续代码。

让定义一个函数来除以两个数字a和b。如果b的值非零,它将正常工作;但如果b的值为零,它将产生错误:

# 示例代码 def divide(a, b): try: result = a / b return result except ZeroDivisionError: return "Error: Division by zero!"

else语句

在Python中,还可以指示程序在没有发生异常时执行某些代码行,使用else子句。现在,如果没有异常发生,希望打印“没有发生错误!”。让看看如何做到这一点:

# 示例代码 try: # 尝试执行的代码 pass except SomeException: # 异常处理代码 pass else: # 如果没有异常发生,执行这里的代码 print("No Error occurred!!")

finally语句

现在,如果需要执行某种动作,无论是否发生错误(如维护日志),可以使用Python中的finally子句。它将始终被执行,无论程序是否遇到任何异常。

将看到如何在本文稍后使用finally子句来写日志。现在,在上述示例中,希望在每次执行后无论是否发生错误都打印a和b的值。让看看如何做到这一点:

# 示例代码 try: # 尝试执行的代码 pass except SomeException: # 异常处理代码 pass else: # 如果没有异常发生,执行这里的代码 pass finally: # 无论是否发生异常,都会执行这里的代码 print("Value of a and b after execution")

Python中异常处理的实际用例

到目前为止,已经看到了一些随机数据的异常处理。让通过一个实际的例子来理解这个概念。有包含员工详细信息的数据,如他们的教育背景、年龄、参加的培训次数等。数据按地区划分为多个目录。同一地区的员工详细信息存储在同一个文件中。

现在,任务是读取所有文件并将它们合并成一个文件。让首先导入一些所需的库。

# 示例代码 import glob import pandas as pd # 使用glob.glob函数和目标目录的路径查看目录结构 directory_structure = glob.glob('/path/to/directory/*')

可以看到文件夹名称表示为一些数字,下一步将遍历每个目录并查看其中的文件:

# 示例代码 for folder in directory_structure: files = glob.glob(folder + '/*.csv') for file in files: print(file)

在每个文件夹中,都有一个CSV文件包含该地区员工的详细信息。可以打开并查看任何CSV文件。以下是region_1.csv文件中数据的样子。它包含属于地区1的员工的详细信息:

现在知道目录和文件名结构有一个模式。在目录n中,有一个名为region_n的CSV文件。所以现在将尝试使用循环读取所有这些文件。

# 示例代码 for i in range(1, 35): # 假设最大数字是34 file_path = f'/path/to/directory/{i}(region_{i}.csv)' try: data = pd.read_csv(file_path) # 处理数据 except FileNotFoundError: print(f'File not found: {file_path}') except Exception as e: print(f'An error occurred: {file_path}, Error: {e}')

可以看到文件region_7不存在。因此,处理这个问题的一个简单方法是在程序中添加一个if条件——如果目录名称是7,则跳过该文件的读取。但如果必须一起读取成千上万的文件,每次遇到错误时更新if条件将是一项繁琐的任务。

在这里,将使用try和except语句来处理错误。如果在运行时读取任何文件时发生任何异常,将跳过该步骤并继续读取下一个文件夹。如果错误是FileNotFoundError,将打印文件名并附上“文件未找到!”;如果发生任何其他错误,将打印文件名并附上“其他错误!”。

try, except和else语句

# 示例代码 parse_error = False file_not_found = False for i in range(1, 35): file_path = f'/path/to/directory/{i}(region_{i}.csv)' try: data = pd.read_csv(file_path) except FileNotFoundError: file_not_found = True print(f'File not found: {file_path}') except pd.errors.ParserError: parse_error = True print(f'Incorrect format: {file_path}') data = pd.read_csv(file_path, skiprows=1) else: # 如果没有异常发生,执行这里的代码 # 将数据帧追加到数据帧列表 pass # 示例代码 for i in range(1, 35): file_path = f'/path/to/directory/{i}(region_{i}.csv)' try: data = pd.read_csv(file_path) except Exception as e: # 处理异常 pass else: # 如果没有异常发生,执行这里的代码 pass finally: # 无论是否发生异常,都会执行这里的代码 # 将文件状态写入日志文件 pass
  • 什么是Lambda函数?Python中Lambda函数的快速指南
  • 学习如何在Pandas中使用Transform函数(含Python代码)
  • 如何在Pandas中使用loc和iloc选择数据(含Python代码!)
  • 高级Python
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485