MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python处理异常与文件操作

2023-06-182.7k 阅读

Python处理异常

在Python编程中,异常处理是一项关键技术,它允许我们在程序运行出现错误时,优雅地处理这些错误,而不是让程序崩溃。

异常基础

Python中的异常是在程序执行过程中出现错误时引发的对象。当Python解释器遇到一个无法处理的错误时,它会创建一个异常对象,并停止当前代码块的执行。例如,当我们尝试用0作为除数时:

try:
    result = 10 / 0
    print(result)
except ZeroDivisionError as e:
    print(f"捕获到异常: {e},不能用零做除数")

在这个例子中,try块包含可能引发异常的代码。当10 / 0执行时,Python会引发一个ZeroDivisionError异常。except块捕获这个异常,并执行其中的代码,打印出错误信息。

常见异常类型

  1. ZeroDivisionError:如上述例子,当进行除法运算,除数为0时触发。
  2. TypeError:当操作或函数应用于不适当类型的对象时触发。例如:
try:
    num = "10" + 5
    print(num)
except TypeError as e:
    print(f"捕获到类型错误异常: {e},字符串和整数不能直接相加")

在这个例子中,我们试图将字符串"10"和整数5相加,这是不允许的,因此会引发TypeError。 3. NameError:当尝试访问一个未定义的变量时触发。例如:

try:
    print(non_existent_variable)
except NameError as e:
    print(f"捕获到名称错误异常: {e},变量未定义")

这里我们尝试打印一个未定义的变量non_existent_variable,从而引发NameError。 4. FileNotFoundError:在尝试打开一个不存在的文件时触发,这在文件操作部分会经常遇到。例如:

try:
    with open('non_existent_file.txt', 'r') as file:
        content = file.read()
        print(content)
except FileNotFoundError as e:
    print(f"捕获到文件未找到异常: {e},文件不存在")

这里我们尝试打开一个不存在的文件non_existent_file.txt,会引发FileNotFoundError

捕获多个异常

有时候,一段代码可能引发多种不同类型的异常。我们可以在一个try块后使用多个except块来捕获不同类型的异常。例如:

try:
    num1 = input("请输入一个数字: ")
    num2 = input("请输入另一个数字: ")
    result = int(num1) / int(num2)
    print(f"结果是: {result}")
except ValueError as e:
    print(f"捕获到值错误异常: {e},输入的不是有效的数字")
except ZeroDivisionError as e:
    print(f"捕获到除零错误异常: {e},除数不能为零")

在这个例子中,try块中的代码可能引发两种异常。如果用户输入的不是有效的数字,会引发ValueError;如果除数为0,会引发ZeroDivisionError。通过多个except块,我们可以分别处理这两种情况。

else子句

try - except结构还可以包含一个else子句。else子句中的代码只有在try块中没有引发任何异常时才会执行。例如:

try:
    num1 = 10
    num2 = 2
    result = num1 / num2
except ZeroDivisionError as e:
    print(f"捕获到异常: {e}")
else:
    print(f"计算结果: {result}")

这里,因为try块中的除法运算不会引发异常,所以else子句中的代码会被执行,打印出计算结果。

finally子句

finally子句无论try块中是否引发异常,都会被执行。它通常用于执行一些清理操作,比如关闭文件、释放资源等。例如:

file = None
try:
    file = open('test.txt', 'w')
    file.write('这是一些测试内容')
except IOError as e:
    print(f"捕获到I/O错误异常: {e}")
finally:
    if file:
        file.close()

在这个例子中,无论try块中写入文件时是否发生异常,finally子句都会确保文件被关闭。从Python 3.2开始,我们可以使用with语句更简洁地处理文件操作,with语句会自动处理文件的关闭,在文件操作部分会详细介绍。

自定义异常

在某些情况下,Python内置的异常类型可能无法满足我们的需求,这时我们可以定义自己的异常类型。自定义异常需要继承自Exception类或其某个子类。例如:

class MyCustomError(Exception):
    pass

def check_number(num):
    if num < 0:
        raise MyCustomError("数字不能为负数")

try:
    check_number(-5)
except MyCustomError as e:
    print(f"捕获到自定义异常: {e}")

在这个例子中,我们定义了一个MyCustomError异常类,它继承自Exceptioncheck_number函数在传入的数字为负数时,会引发这个自定义异常。try - except块捕获并处理这个异常。

Python文件操作

文件操作是Python编程中非常常见的任务,它允许我们读取、写入和修改文件中的数据。

文件打开与关闭

在Python中,使用open()函数来打开一个文件。open()函数接受两个参数,第一个是文件名,第二个是打开模式。例如:

file = open('example.txt', 'r')
content = file.read()
print(content)
file.close()

这里,我们以只读模式('r')打开example.txt文件,然后使用read()方法读取文件内容并打印,最后使用close()方法关闭文件。关闭文件是很重要的,因为它可以释放系统资源,确保数据被正确写入磁盘。

常见的打开模式有:

  1. 'r':只读模式。如果文件不存在,会引发FileNotFoundError
  2. 'w':写入模式。如果文件不存在,会创建新文件;如果文件已存在,会清空文件内容。
  3. 'a':追加模式。如果文件不存在,会创建新文件;如果文件已存在,会在文件末尾追加内容。
  4. 'x':独占创建模式。如果文件已存在,会引发FileExistsError
  5. 'b':二进制模式,可与其他模式组合使用,如'rb'表示以二进制只读模式打开文件,常用于处理非文本文件,如图像、音频等。
  6. 't':文本模式,默认模式。可与其他模式组合使用,如'rt',一般处理文本文件。

使用with语句

with语句提供了一种更安全、更简洁的文件操作方式,它会在代码块结束时自动关闭文件,无需手动调用close()方法。例如:

with open('example.txt', 'r') as file:
    content = file.read()
    print(content)

在这个例子中,当with代码块结束时,文件会自动关闭,无论代码块中是否发生异常。这大大简化了文件操作的代码,同时也避免了因忘记关闭文件而导致的资源泄漏问题。

文件读取

  1. read()方法:读取整个文件内容,返回一个字符串(如果是文本文件)或字节对象(如果是二进制文件)。例如:
with open('example.txt', 'r') as file:
    content = file.read()
    print(content)
  1. readline()方法:逐行读取文件内容,每次调用返回一行内容,包括行末的换行符。例如:
with open('example.txt', 'r') as file:
    line = file.readline()
    while line:
        print(line.strip())
        line = file.readline()

这里使用strip()方法去除每行末尾的换行符。 3. readlines()方法:读取文件的所有行,返回一个包含每行内容的列表,每行末尾包含换行符。例如:

with open('example.txt', 'r') as file:
    lines = file.readlines()
    for line in lines:
        print(line.strip())

文件写入

  1. write()方法:将字符串(如果是文本模式)或字节对象(如果是二进制模式)写入文件。例如:
with open('new_file.txt', 'w') as file:
    file.write('这是新写入的内容\n')

这里使用\n表示换行符。 2. writelines()方法:接受一个字符串序列(如列表),将其中的字符串逐行写入文件。例如:

lines = ['第一行内容\n', '第二行内容\n', '第三行内容\n']
with open('new_lines.txt', 'w') as file:
    file.writelines(lines)

文件定位

在文件操作过程中,有时需要在文件的不同位置进行读写操作,这就涉及到文件定位。tell()方法用于获取当前文件指针的位置,seek()方法用于移动文件指针到指定位置。例如:

with open('example.txt', 'r') as file:
    print(f"初始位置: {file.tell()}")
    content = file.read(5)
    print(f"读取5个字符: {content}")
    print(f"当前位置: {file.tell()}")
    file.seek(10)
    print(f"移动到位置10后,当前位置: {file.tell()}")
    content = file.read(5)
    print(f"从位置10读取5个字符: {content}")

在这个例子中,tell()方法返回当前文件指针的位置(以字节为单位,对于文本文件,在某些编码下可能与字符数不完全对应)。seek()方法接受一个偏移量参数,将文件指针移动到指定位置。

二进制文件操作

处理二进制文件(如图片、音频、视频等)时,需要以二进制模式打开文件。例如,复制一个图片文件:

with open('source_image.jpg', 'rb') as source_file:
    with open('destination_image.jpg', 'wb') as destination_file:
        while True:
            data = source_file.read(1024)
            if not data:
                break
            destination_file.write(data)

在这个例子中,我们以二进制只读模式打开源图片文件source_image.jpg,以二进制写入模式打开目标文件destination_image.jpg。然后通过循环读取源文件的数据块(每次读取1024字节),并写入目标文件,直到源文件读取完毕。

文件和目录操作的其他模块

除了基本的文件操作函数外,Python还提供了一些用于处理文件和目录的模块,如os模块和pathlib模块。

  1. os模块:提供了许多与操作系统交互的功能,包括文件和目录操作。例如,创建目录、删除目录、重命名文件等。
import os

# 创建目录
if not os.path.exists('new_directory'):
    os.mkdir('new_directory')

# 删除目录(目录必须为空)
# os.rmdir('new_directory')

# 重命名文件
os.rename('old_file.txt', 'new_file.txt')
  1. pathlib模块:在Python 3.4及以上版本可用,提供了面向对象的方式来处理文件路径。它使路径操作更加直观和跨平台。例如:
from pathlib import Path

# 创建目录
new_dir = Path('new_directory')
new_dir.mkdir(exist_ok=True)

# 检查文件是否存在
file_path = Path('example.txt')
if file_path.exists():
    print(f"{file_path} 存在")

# 获取文件大小
if file_path.is_file():
    size = file_path.stat().st_size
    print(f"{file_path} 的大小是 {size} 字节")

pathlib模块中的Path类提供了丰富的方法来操作路径,如joinpath()用于拼接路径,parent属性用于获取父目录等。

文件操作中的异常处理

在文件操作过程中,可能会遇到各种异常,如文件不存在、权限不足等。合理地处理这些异常可以使程序更加健壮。例如:

try:
    with open('non_existent_file.txt', 'r') as file:
        content = file.read()
        print(content)
except FileNotFoundError as e:
    print(f"捕获到文件未找到异常: {e},请检查文件名和路径")
except PermissionError as e:
    print(f"捕获到权限错误异常: {e},可能没有访问该文件的权限")

在这个例子中,我们尝试打开一个不存在的文件,可能会引发FileNotFoundError异常;如果没有足够的权限访问文件,可能会引发PermissionError异常。通过try - except结构,我们可以捕获并处理这些异常,避免程序崩溃。

文件编码处理

在处理文本文件时,文件的编码格式很重要。不同的编码格式可能导致读取或写入文件时出现乱码等问题。open()函数可以通过encoding参数指定文件的编码格式。常见的编码格式有'utf - 8''gbk'等。例如:

# 以UTF - 8编码写入文件
with open('utf8_file.txt', 'w', encoding='utf - 8') as file:
    file.write('这是UTF - 8编码的文本')

# 以GBK编码读取文件(假设文件实际是GBK编码)
try:
    with open('gbk_file.txt', 'r', encoding='gbk') as file:
        content = file.read()
        print(content)
except UnicodeDecodeError as e:
    print(f"捕获到解码错误异常: {e},可能编码格式不正确")

在这个例子中,我们分别演示了以UTF - 8编码写入文件和以GBK编码读取文件。如果编码格式指定错误,可能会引发UnicodeDecodeError异常。

通过深入理解Python的异常处理和文件操作技术,开发者可以编写出更加健壮、可靠且功能丰富的程序,能够有效地处理各种错误情况,并灵活地与文件系统进行交互。无论是开发小型脚本还是大型应用程序,这些技术都是不可或缺的。