好的,我们来学习第八章。在之前的章节里,我们的程序产生的所有数据,比如变量、列表,都存放在内存里。程序一旦结束,这些数据就消失了。这一章,我们将学习如何将数据永久地保存在文件中,并学习一套“安全带”机制——异常处理,来保证我们的程序在遇到意外情况时不会轻易“崩溃”。


第八章:文件操作与异常处理

8.1 读取与写入文本文件

核心比喻:记事本

  • 文件:就像你电脑里的一个.txt记事本文件。

  • 打开文件 open():就像你双击打开这个记事本。打开时你需要决定是想**读('r')里面的内容,还是想写('w')**新的内容。

  • 读/写操作:执行实际的读写动作。

  • 关闭文件 close():就像你点击记事本的关闭按钮,保存你的修改。这是一个非常重要的步骤,忘记关闭可能会导致数据丢失。

第一步:写入一个全新的文件 (Write Mode - 'w')

写入模式 'w' 会创建一个新文件。如果文件已存在,它会清空所有旧内容,然后写入新内容。

  1. 打开你的Linux终端,我们先用ls命令看看当前目录下有什么。

  2. 进入python3交互模式。

  3. 打开文件。我们准备创建一个名为shopping_list.txt的文件。encoding='utf-8'是处理中文等非英文字符的标准做法,强烈建议总是加上。

    Python

    >>> f = open('shopping_list.txt', 'w', encoding='utf-8')
    
  4. 写入内容。使用.write()方法。\n是一个特殊字符,代表“换行”。

    Python

    >>> f.write('鸡蛋\n')
    >>> f.write('牛奶\n')
    >>> f.write('面包')
    
  5. 关闭文件。这是保存写入内容的关键一步!

    Python

    >>> f.close()
    
  6. 验证结果。按Ctrl+D退出Python。在终端里用cat命令查看文件内容。

    Bash

    cat shopping_list.txt
    

    你会看到我们写入的三行内容。

第二步:读取一个已存在的文件 (Read Mode - 'r')

  1. 再次进入python3交互模式。

  2. 只读模式打开我们刚才创建的文件。

    Python

    >>> f = open('shopping_list.txt', 'r', encoding='utf-8')
    
  3. 读取全部内容。使用.read()方法。

    Python

    >>> content = f.read()
    
  4. 关闭文件

    Python

    >>> f.close()
    
  5. 现在,文件的所有内容都保存在content这个字符串变量里了。

    Python

    >>> print(content)
    鸡蛋
    牛奶
    面包
    

第三步:在文件末尾追加内容 (Append Mode - 'a')

如果你不想清空文件,只想在后面添加新内容,就用'a'模式。

Python

>>> f = open('shopping_list.txt', 'a', encoding='utf-8')
>>> f.write('\n果汁') # 先换行再追加
>>> f.close()

现在你再用cat shopping_list.txt查看,会发现“果汁”被加在了最后。


8.2 处理CSV与JSON文件

纯文本文件虽然简单,但如果数据有结构(比如表格),用专门的格式会更方便。CSV和JSON就是两种最常见的数据交换格式。

CSV:像电子表格一样的文本

CSV (Comma-Separated Values) 文件就是用逗号分隔值的文本文件,每一行代表一条记录。Python有内置的csv模块来轻松处理它。

  1. 首先,我们用nano创建一个students.csv文件。

    Bash

    nano students.csv
    

    输入以下内容(这就是CSV格式):

    代码段

    name,age,grade
    Alice,20,A
    Bob,22,B
    Charlie,21,A
    

    保存并退出。

  2. python3交互模式中,读取这个文件。

    Python

    >>> import csv
    >>> with open('students.csv', 'r', encoding='utf-8') as file:
    ...     reader = csv.reader(file)
    ...     for row in reader:
    ...         print(row)
    ...
    

    讲解:我们使用了with语句(稍后会详细讲),它能自动帮我们关闭文件。csv.reader会把每一行转换成一个字符串列表。你会看到输出:

    ['name', 'age', 'grade']
    ['Alice', '20', 'A']
    ['Bob', '22', 'B']
    ['Charlie', '21', 'A']
    

JSON:像Python字典和列表一样的文本

JSON (JavaScript Object Notation) 是一种轻量级的数据格式,它的语法和Python的字典、列表几乎一样。它是现代网络API通信的标准。Python用json模块来处理。

  1. python3交互模式中,我们来操作JSON。

  2. 将Python字典转换为JSON字符串(序列化)

    Python

    >>> import json
    >>> user_profile = {
    ...     "name": "David",
    ...     "age": 35,
    ...     "is_active": True,
    ...     "courses": ["Python", "Machine Learning"]
    ... }
    >>> # json.dumps() 将字典转为JSON字符串, indent=4让格式更美观
    >>> user_json = json.dumps(user_profile, indent=4, ensure_ascii=False)
    >>> print(user_json)
    

    你会看到一段格式优美的、和字典长得一模一样的文本。

  3. 将JSON字符串转换回Python字典(反序列化)

    Python

    >>> # 假设 user_json 是从文件或网络获取的字符串
    >>> restored_dict = json.loads(user_json)
    >>> print(restored_dict)
    {'name': 'David', 'age': 35, 'is_active': True, 'courses': ['Python', 'Machine Learning']}
    >>> print(restored_dict['name'])
    David
    

8.3 try...except:优雅地处理错误

核心比喻:Plan B

在写程序时,很多操作都可能失败。比如你要读取的文件可能不存在,你要转换成数字的字符串可能是"hello",你要除以的数可能是0。如果发生这些异常 (Exception),程序默认会立刻崩溃并报错。

try...except语句就是给程序一个Plan B

  • try 代码块:把你认为可能出错的代码放在这里(Plan A)。

  • except 代码块:如果try里的代码真的出错了,程序不会崩溃,而是会立即跳转到except代码块里执行(Plan B)。

第一步:体验一次程序崩溃

Python

>>> age_str = "二十"
>>> age_int = int(age_str) # 这行会出错,因为“二十”无法转成数字

程序会抛出ValueError并终止。

第二步:使用try...except来避免崩溃

Python

>>> age_str = "二十"
>>> try:
...     print("正在尝试转换...")
...     age_int = int(age_str) # Plan A: 尝试执行这句危险代码
...     print(f"转换成功,年龄是 {age_int}")
... except ValueError: # Plan B: 如果上面的代码触发了 ValueError
...     print("转换失败!请输入一个阿拉伯数字。")
...
>>> print("程序继续运行...")

观察输出:你会看到“正在尝试转换...”,然后是“转换失败!...”,最后是“程序继续运行...”。程序没有崩溃,而是执行了我们的Plan B,然后继续向下执行。这就是优雅地处理错误。

你可以捕捉不同类型的异常,比如FileNotFoundError, ZeroDivisionError等。


8.4 抛出异常:raise

有时候,Python本身不认为代码有错,但根据你的业务逻辑,它就是错的。比如,函数要求输入一个正数,但用户输入了负数。这时,你可以主动地、人为地触发一个异常,来通知程序的其他部分“这里出问题了!”。这个动作就是抛出 (raise) 异常。

一步一步实践:

  1. 我们编写一个设置密码的函数,逻辑要求密码长度不能少于8位。

    Python

    >>> def set_password(password):
    ...     if len(password) < 8:
    ...         # 密码长度不够,这是一个业务逻辑错误,我们主动抛出异常
    ...         raise ValueError("密码长度不能少于8位!")
    ...     print("密码设置成功。")
    ...
    
  2. 使用一个合法的密码调用函数:

    Python

    >>> set_password("MySuperSecret123")
    密码设置成功。
    
  3. 使用一个不合法的密码调用函数:

    Python

    >>> set_password("12345")
    

    程序立刻被中断,并抛出了我们自己定义的ValueError,显示的消息也是我们自己写的。

raisetry...except 经常配合使用:你可以在一个地方raise异常,然后在调用这个地方的更高层级代码里用try...except来捕捉并处理这个异常。


8.5 上下文管理器与with语句

核心比喻:自动关门的冰箱

我们回到8.1节的文件操作。我们每次都必须手动执行f.close()。如果中间代码出了错,f.close()可能永远不会被执行,文件就会一直被占用,这是一种资源泄露。

with语句(也叫上下文管理器)就是为了解决这个问题而生的,它能自动管理资源的获取和释放。对于文件来说,它能保证文件在用完后一定会被自动关闭,无论中间是否发生错误。

一步一步体验with语句的魔力:

  1. 传统方式(需要手动close

    Python

    f = open('my_file.txt', 'w', encoding='utf-8')
    f.write('hello')
    f.close()
    
  2. 使用with语句(现代、安全的方式)

    Python

    >>> with open('my_file.txt', 'w', encoding='utf-8') as f:
    ...     f.write('hello, with statement!')
    ...     # 在这个缩进块里,文件是打开的,变量 f 可以使用
    ...
    >>> # 退出缩进块后,Python 会自动帮你执行 f.close()
    

    讲解

    • with open(...) as f::打开文件并将其赋值给变量f

    • 缩进的代码块就是with管理的范围。

    • 当代码执行离开这个缩进块时(无论是正常结束还是发生错误),Python都会自动、必定地关闭文件。

给小白的最终建议永远、永远、永远使用 with open(...) 的方式来处理文件! 这是最安全、最简洁、最现代的Pythonic方式,它能让你免于忘记关闭文件的烦恼。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐