Python 异常处理与文件操作全解析

一、异常处理

1. 什么是异常

在程序执行过程中,当 Python 无法正常处理程序时,就会发生异常。异常是 Python 的对象,代表着程序运行过程中出现的错误。如果不捕获和处理异常,程序会终止执行。

>>> print(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>

2. 异常处理基础

(1)处理方式

try/except 语句是处理异常的基本方式,用于检测 try 语句块中的错误,并让 except 语句捕获异常信息并处理,避免程序因异常而终止。

(2)语法格式
try:
    <语句>  # 运行可能出错的代码
except <异常名>:
    <语句>  # 当 try 部分引发指定异常时执行
(3)工作原理

执行 try 子句时,Python 会在当前程序上下文做标记。若发生异常,程序跳回标记处并执行对应的 except 子句;若未发生异常,则跳过 except 子句,继续执行后续代码。

(4)代码示例
def exp(x, y):
    try:
        a = x / y
        print(f'a={a}')
        return a
    except Exception:
        print('程序出现异常信息:除数为0')

exp(2, 0)  # 调用函数,传入除数为0的参数

3. 抛出异常

若只想检测异常是否发生而不处理,可以使用 raise 语句再次抛出异常,以获取更详细的异常信息。

# 示例1:不再次抛出异常
try:
    raise NameError('This is NameError')
except NameError:
    print('An exception happened')  # 仅输出提示信息

# 示例2:再次抛出异常
try:
    raise NameError('This is NameError')
except NameError:
    print('An exception happened')
    raise  # 再次抛出异常,显示详细异常信息

输出结果

An exception happened
An exception happened
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: This is NameError

4. 捕捉多个异常

(1)语法格式
try:
    <语句>  # 运行可能出错的代码
except <异常名1><语句>  # 处理异常名1对应的异常
except <异常名2> as <数据>:
    <语句>  # 处理异常名2对应的异常,并获取附加数据
(2)代码示例(分块捕捉)
def multi_exception(x, y):
    try:
        a = x / y
        # b = name  # 若取消注释,当触发NameError时会被对应except捕获
    except ZeroDivisionError:
        print('this is ZeroDivisionError')
    except NameError:
        print('this is NameError')

multi_exception(2, 0)  # 触发ZeroDivisionError
(3)代码示例(一个块捕捉多个异常)
def multi_exception(x, y):
    try:
        a = x / y
        return a
    except (ZeroDivisionError, TypeError, NameError) as e:
        print(e)  # 打印捕获到的异常信息

a = multi_exception(2, 0)  # 触发ZeroDivisionError并打印异常信息

5. 捕捉异常对象

使用 as e 形式可以在 except 子句中访问异常对象本身,获取真实的异常信息。

def multi_exception(x, y):
    try:
        a = x / y
        return a
    except (ZeroDivisionError, TypeError, NameError) as e:
        print(e)  # 输出异常对象的具体信息

a = multi_exception(2, 0)  # 输出:division by zero

6. 全捕捉(不推荐)

使用不带具体异常名的 except 可以捕捉所有异常,但可能隐藏未预料到的错误,不建议使用。

def multi_exception(x, y):
    try:
        a = x / y
        return a
    except:
        print('Error happened')  # 输出自定义提示,无法得知具体异常

a = multi_exception(2, '')  # 触发TypeError,仅输出自定义提示

7. 异常中的 else 子句

try 子句执行时未发生异常,会执行 else 子句中的语句,有助于区分正常执行和异常处理的逻辑。

try:
    <语句>  # 运行可能出错的代码
except <异常名1><语句>  # 处理异常1
except <异常名2> as <数据>:
    <语句>  # 处理异常2并获取数据
else:
    <语句>  # 未发生异常时执行

8. 自定义异常

通过继承 Exception 类可以定义自定义异常,用于处理特定业务场景下的错误。

class MyError(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return '这是一个自定义异常'  # 定义异常描述信息

def my_error_test():
    try:
        raise MyError()  # 主动抛出自定义异常
    except MyError as e:
        print('异常信息:', e)

my_error_test()  # 输出:异常信息: 这是一个自定义异常

9. finally 子句

finally 子句与 try 配合使用,无论是否发生异常,finally 中的代码都会执行,常用于资源释放(如关闭文件、数据库连接)。

def use_finally(x, y):
    try:
        a = x / y
    except ZeroDivisionError:
        print("异常信息:分母为0")
    finally:
        print('无论有没有异常,我都会被执行')

use_finally(2, 0)  # 先执行except,再执行finally

10. 异常与函数

异常信息以堆栈形式抛出(先进后出),从下往上查看可追溯异常根源。

def division_fun(x, y):
    return x / int(y)

def exp_fun(x, y):
    return division_fun(x, y) * 10

def main(x, y):
    exp_fun(x, y)

main(2, 0)  # 触发ZeroDivisionError,异常堆栈从main追溯到division_fun

二、文件操作和基本方法

1. 文件操作基础

(1)语法格式
open(file_name[, access_mode][, buffering])
(2)参数解析
  • file_name:字符串,指定要访问的文件名称(包含路径)。
  • access_mode:可选参数,打开文件的模式(默认只读 r)。
  • buffering:可选参数,控制文件缓存(0 无缓存、1 行缓存、>1 指定缓存大小、负数使用系统默认)。
  • 返回值:File 对象,代表计算机中的一个文件。
(3)路径概念
  • 绝对路径:从根文件夹开始(如 Windows 的 C:/test.txt,Linux 的 /home/test.txt)。
  • 相对路径:相对于程序当前工作目录的路径(. 代表当前目录)。
(4)代码示例
path = "D:\\python\\demo.txt"  # Windows 路径(注意转义符)
f = open(path, "w")
print(f.name)  # 输出文件路径
f.close()  # 关闭文件
(5)文件模式
模式 描述
r 只读(文件不存在则报错)
w 只写(文件不存在则创建,存在则覆盖)
a 追加(文件不存在则创建,在末尾写入)
r+ 读写(文件不存在则报错)
w+ 读写(文件不存在则创建,存在则覆盖)
a+ 读写(文件不存在则创建,在末尾写入)
rb 二进制只读
wb 二进制只写
ab 二进制追加

2. 基本文件操作

(1)读取与写入数据
  • read([count]):从文件读取字符串,count 为读取的字节数(默认读取全部)。
  • write(str):向文件写入字符串,返回写入的字符数。

读取示例

path = "demo.txt"
with open(path, "r") as f:  # 使用with自动关闭文件
    print(f.read())  # 读取全部内容

写入示例

path = "demo.txt"
with open(path, "w") as f:
    f.write("Hello World!")  # 写入内容(覆盖原有内容)

with open(path, "r") as f:
    print(f.read())  # 输出:Hello World!

追加示例

path = "demo.txt"
with open(path, "a") as f:
    f.write("\nHello Again!")  # 追加内容到末尾

with open(path, "r") as f:
    print(f.read())  # 输出原有内容+追加内容
(2)读写行
  • readlines():读取所有行,返回字符串列表。
  • writelines(list):向文件写入字符串列表。
path = "demo.txt"
# 写入多行
with open(path, 'w') as f:
    str_list = ['Hello World!\n', 'Welcome!\n']
    f.writelines(str_list)

# 读取多行
with open(path, 'r') as f:
    print(f.readlines())  # 输出:['Hello World!\n', 'Welcome!\n']
(3)关闭文件
  • 方法一:使用 try...except...finally 确保文件关闭。
path = "demo.txt"
fname = None
try:
    fname = open(path, "w")
    fname.write("Hello")
except Exception as e:
    print(e)
finally:
    if fname:
        fname.close()  # 确保文件关闭
  • 方法二:使用 with 语句(推荐),自动调用 close()
path = "demo.txt"
with open(path, "w") as f:  # 退出with块时自动关闭文件
    f.write("Hello")
(4)文件重命名

使用 os 模块的 rename 方法,需导入 os 模块。

import os
try:
    os.rename("old.txt", "new.txt")  # 将old.txt重命名为new.txt
except Exception as e:
    print(f"重命名失败:{e}")
(5)删除文件

使用 os 模块的 remove 方法,需导入 os 模块。

import os
try:
    os.remove("demo.txt")  # 删除文件
except Exception as e:
    print(f"删除失败:{e}")  # 处理文件不存在等异常

总结

本文详细介绍了 Python 中的异常处理机制(包括异常捕获、抛出、自定义异常等)和文件操作方法(包括文件读写、路径处理、重命名、删除等)。合理使用异常处理可以提高程序的健壮性,而规范的文件操作则能确保数据的安全读写。在实际开发中,建议结合 with 语句进行文件操作,以简化资源管理;同时,避免使用全捕捉异常,应针对性地处理可能发生的错误。

更多推荐