Compare commits

..

2 Commits

Author SHA1 Message Date
f7c820b0f4 feat(python进阶): 新增文件与目录操作课程 2026-08-03 22:01:22 +08:00
691405f380 feat(python进阶): 新增模块与包课程 2026-08-03 21:26:53 +08:00
11 changed files with 1093 additions and 13 deletions

View File

@@ -0,0 +1,402 @@
# 第 2-1 课:模块与包
## 一、本课目标
完成本课后,你将能够:
1. 说出模块和包分别是什么;
2. 解释为什么要把较长的程序拆分成多个文件;
3. 使用 `import` 导入模块;
4. 使用 `from...import...` 导入指定内容;
5. 创建并使用自己的模块和包;
6. 理解 `if __name__ == "__main__":` 的基本作用。
## 二、前置知识
学习本课前,需要掌握:
- 变量和基本数据类型;
- 列表与字典;
- 条件判断与循环;
- 函数、参数和返回值;
- 知道 Python 代码保存在 `.py` 文件中。
本课是 Python 进阶阶段的第一课,但不会使用复杂语法。
## 三、模块是什么
模块Module通常就是一个保存了 Python 代码的 `.py` 文件。
前面的课程大多把函数和主程序写在同一个文件中。程序越来越大后,这种方式会产生三个问题:
1. 文件太长,不容易阅读;
2. 不同功能混在一起,不容易修改;
3. 已经写好的函数不方便在其他程序中重复使用。
把相关函数放进单独文件,可以让代码职责更清晰。例如:
```text
agent_tools.py 保存 Agent 工具相关函数
module_example.py 组织程序运行流程
```
`agent_tools.py` 就是一个自定义模块。
## 四、使用 `import` 导入模块
导入Import表示让当前文件能够使用另一个模块中的内容。
### 4.1 导入标准库模块
标准库Standard Library是安装 Python 时自带的一组模块,不需要另外下载。本课使用 `random` 模块随机选择列表元素:
```python
import random
tools = ["搜索", "终端", "计算器"]
recommended_tool = random.choice(tools)
print(recommended_tool)
```
这里:
- `import random` 导入整个模块;
- `random.choice()` 表示调用 `random` 模块中的 `choice()` 函数;
- 函数会从列表中随机选择一个元素,因此每次结果可能不同。
### 4.2 导入自己的模块
课程目录中的 `agent_tools.py` 定义了函数和变量。在同一目录的 `module_example.py` 中可以这样使用:
```python
import agent_tools
tool_count = agent_tools.get_tool_count(agent_tools.DEFAULT_TOOLS)
print(tool_count)
```
导入时不写 `.py`,因此使用的是 `import agent_tools`,不是 `import agent_tools.py`
通过 `模块名.名称` 可以清楚看出这个变量或函数来自哪里。
## 五、使用 `from...import...`
如果当前文件只需要模块中的少量内容,可以导入指定名称:
```python
from agent_tools import build_agent_description
description = build_agent_description("代码助手", "gpt-5")
print(description)
```
导入后可以直接写函数名,不再需要添加 `agent_tools.`
两种写法都正确:
```python
import agent_tools
agent_tools.build_agent_description("代码助手", "gpt-5")
```
```python
from agent_tools import build_agent_description
build_agent_description("代码助手", "gpt-5")
```
入门阶段建议优先使用清晰、容易看出来源的写法。不要使用 `from agent_tools import *`,因为星号会一次导入许多名称,容易造成重名和阅读困难。
## 六、导入模块时会发生什么
第一次导入模块时Python 会从上到下执行模块中的代码。函数定义只是创建函数,不会自动调用函数;但直接写在文件最外层的 `print()` 会立即执行。
为了区分“直接运行文件”和“把文件作为模块导入”,可以使用:
```python
if __name__ == "__main__":
main()
```
`__name__` 是 Python 自动提供的特殊变量:
- 直接运行当前文件时,`__name__` 的值是 `"__main__"`
- 当前文件被其他文件导入时,`__name__` 的值是模块名。
因此,可以把模块的测试代码放进 `main()`,再通过入口判断调用:
```python
def main():
print("正在测试模块。")
if __name__ == "__main__":
main()
```
这样直接运行模块时会执行测试,导入模块时不会意外输出测试文字。
## 七、包是什么
Package是用于组织多个模块的文件夹。
本课示例结构如下:
```text
agent_package/
├── __init__.py
└── status_text.py
```
`__init__.py` 用来明确表示这个目录是一个 Python 包。本课暂时不在其中编写功能,只保留说明注释。
从包中的模块导入函数:
```python
from agent_package.status_text import get_status_text
status_text = get_status_text(True)
print(status_text)
```
可以把导入路径从左到右理解为:
```text
agent_package 包 → status_text 模块 → get_status_text 函数
```
## 八、示例文件
本课包含以下示例:
```text
02_python进阶/2_1_模块与包/
├── README.md
├── module_example.py
├── agent_tools.py
├── practice.py
└── agent_package/
├── __init__.py
└── status_text.py
```
- `module_example.py`:完整主程序;
- `agent_tools.py`:自己编写的模块;
- `agent_package/`:自己编写的简单包;
- `practice.py`:课堂练习。
## 九、运行方法
打开 PowerShell进入项目根目录
```powershell
cd F:\PyCharm\PythonLearn
```
运行完整示例:
```powershell
python .\02_python进阶\2_1_模块与包\module_example.py
```
直接运行自定义模块的测试:
```powershell
python .\02_python进阶\2_1_模块与包\agent_tools.py
```
完成练习后运行:
```powershell
python .\02_python进阶\2_1_模块与包\practice.py
```
## 十、运行结果
运行 `module_example.py` 时,会看到类似结果:
```text
一、标准库模块
随机推荐工具:搜索
==============================
二、自定义模块
默认工具:['搜索', '终端']
默认工具数量2
代码助手 使用 gpt-5 模型
==============================
三、自定义包
Agent 状态:启用
```
第一部分使用了随机选择,因此也可能显示“终端”或“计算器”,这不是错误。
运行 `agent_tools.py` 时,预期看到:
```text
正在测试 agent_tools 模块。
默认工具数量2
```
## 十一、关键代码执行顺序
运行 `module_example.py`Python 大致按照以下顺序工作:
1. 执行文件顶部的导入语句;
2. 找到并加载标准库模块 `random`
3. 找到同一目录中的 `agent_tools.py`
4. 找到 `agent_package` 包中的 `status_text.py`
5. 创建当前文件中定义的函数;
6. 执行文件末尾的程序入口判断;
7. 因为当前文件是直接运行的,所以调用 `main()`
8. `main()` 依次调用三个演示函数并输出结果。
导入 `agent_tools.py` 时,它的入口判断不成立,所以不会自动执行 `show_module_test()`
## 十二、常见错误
### 12.1 导入时写了 `.py`
错误写法:
```python
import agent_tools.py
```
正确写法:
```python
import agent_tools
```
模块名不包含文件扩展名 `.py`
### 12.2 文件名与导入名不一致
如果文件名是 `agent_tools.py`,就应使用 `import agent_tools`。少写字母或使用不同名称,会出现:
```text
ModuleNotFoundError: No module named 'agent_tool'
```
中文解释Python 没有找到名为 `agent_tool` 的模块。请检查文件名、导入名和运行目录。
### 12.3 导入整个模块后直接调用函数
如果使用:
```python
import agent_tools
```
就要通过模块名调用:
```python
agent_tools.get_tool_count([])
```
直接写 `get_tool_count([])` 会出现名称未定义错误。
### 12.4 自定义模块名与标准库重名
不要把自己的文件命名为 `random.py`,否则 `import random` 可能导入自己的文件,而不是 Python 标准库模块。
### 12.5 导入模块时出现意外输出
如果测试用的 `print()` 直接写在模块最外层,导入模块时也会执行。把测试代码放进 `main()`,再使用程序入口判断。
### 12.6 包或模块不在预期位置
本课请保持示例目录结构不变,并从项目根目录执行讲义中的命令。目录位置错误会导致 Python 找不到需要导入的内容。
## 十三、课堂练习
打开 `practice.py`,按照注释依次完成五部分:
1. 创建 `calculator.py` 模块;
2. 分别使用两种方式导入加法函数;
3. 为模块添加安全的测试入口;
4. 创建 `text_package` 包;
5. 从包中的模块导入文本处理函数。
建议先独立完成。如果遇到困难,先检查文件名、目录位置和导入语句是否一致。
## 十四、参考答案
请先独立练习,再展开查看。
<details>
<summary>查看参考答案</summary>
`calculator.py`
```python
def add(first, second):
"""返回两个数字相加的结果。"""
return first + second
def main():
"""测试当前模块的加法功能。"""
print("正在测试计算模块。")
if __name__ == "__main__":
main()
```
`text_package/__init__.py`
```python
# 这个文件表示 text_package 是一个 Python 包。
```
`text_package/text_tools.py`
```python
def make_title(text):
"""为文本添加标题装饰。"""
return f"=== {text} ==="
```
`practice.py` 中需要补充的核心代码:
```python
import calculator
from calculator import add
from text_package.text_tools import make_title
result = calculator.add(10, 20)
print(f"计算结果:{result}")
new_result = add(5, 8)
print(f"新的计算结果:{new_result}")
title = make_title("Python 学习")
print(title)
```
</details>
## 十五、本课小结
- 模块通常是一个 `.py` 文件;
- 模块可以拆分功能,并让代码在多个程序中重复使用;
- `import 模块名` 会导入整个模块;
- `from 模块名 import 名称` 会导入指定内容;
- `if __name__ == "__main__":` 可以避免导入模块时自动执行测试或主程序;
- 包是用于组织多个模块的文件夹;
- 可以使用点号表示“包、模块、名称”之间的层级关系。
## 十六、验收标准
完成本课时,应满足以下条件:
- 可以成功运行 `module_example.py`
- 可以解释模块与包的区别;
- 可以使用两种方式导入模块内容;
- 可以创建并导入自己的 `.py` 模块;
- 可以解释入口判断的基本作用;
- 可以创建包含 `__init__.py` 的简单包;
- 可以完成 `practice.py` 中的五部分练习;
- 运行练习时得到 `30``13``=== Python 学习 ===`
- 导入 `calculator` 时不会自动输出模块测试文字。

View File

@@ -0,0 +1,4 @@
# 这个文件表示 agent_package 是一个 Python 包。
#
# 包就是用于组织多个模块的文件夹。
# 目前先保留简单注释,后续课程会继续学习更复杂的包结构。

View File

@@ -0,0 +1,9 @@
# 第 2-1 课示例:包中的模块
def get_status_text(enabled):
"""把布尔值状态转换成中文文本。"""
if enabled:
return "启用"
return "停用"

View File

@@ -0,0 +1,29 @@
# 第 2-1 课示例:自定义模块
#
# 模块就是一个 Python 文件。
# 这个文件集中保存与 Agent 工具有关的函数,供其他文件导入使用。
DEFAULT_TOOLS = ["搜索", "终端"]
def get_tool_count(tools):
"""返回工具列表中的工具数量。"""
return len(tools)
def build_agent_description(name, model):
"""根据名称和模型生成 Agent 描述。"""
return f"{name} 使用 {model} 模型"
def show_module_test():
"""输出本模块的测试结果。"""
print("正在测试 agent_tools 模块。")
print(f"默认工具数量:{get_tool_count(DEFAULT_TOOLS)}")
# 只有直接运行本文件时,才执行下面的测试代码。
# 其他文件导入本模块时,不会自动执行测试。
if __name__ == "__main__":
show_module_test()

View File

@@ -0,0 +1,63 @@
# 第 2-1 课完整示例:模块与包
#
# 本文件依次演示:
# 1. 使用 import 导入 Python 标准库模块;
# 2. 使用 import 导入自己编写的模块;
# 3. 使用 from...import... 导入指定内容;
# 4. 从自定义包中导入模块;
# 5. 使用程序入口判断组织主程序。
import random
import agent_tools
from agent_tools import build_agent_description
from agent_package.status_text import get_status_text
def print_separator():
"""输出分隔线,让不同示例更容易阅读。"""
print("=" * 30)
def show_standard_library_example():
"""演示使用标准库模块生成随机推荐。"""
tools = ["搜索", "终端", "计算器"]
recommended_tool = random.choice(tools)
print(f"随机推荐工具:{recommended_tool}")
def show_custom_module_example():
"""演示使用自己编写的 agent_tools 模块。"""
tool_count = agent_tools.get_tool_count(agent_tools.DEFAULT_TOOLS)
print(f"默认工具:{agent_tools.DEFAULT_TOOLS}")
print(f"默认工具数量:{tool_count}")
description = build_agent_description("代码助手", "gpt-5")
print(description)
def show_package_example():
"""演示从自定义包中导入并使用函数。"""
enabled = True
status_text = get_status_text(enabled)
print(f"Agent 状态:{status_text}")
def main():
"""按照顺序运行本课的三个示例。"""
print("一、标准库模块")
show_standard_library_example()
print_separator()
print("二、自定义模块")
show_custom_module_example()
print_separator()
print("三、自定义包")
show_package_example()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,46 @@
# 第 2-1 课课堂练习:模块与包
#
# 请先完成讲义中的学习和示例运行,再按照顺序完成练习。
# 不要删除题目和预期结果;每完成一部分就运行一次。
# 第一部分:创建自定义模块
# 1. 在当前课程目录创建 calculator.py。
# 2. 在 calculator.py 中定义 add(first, second) 函数。
# 3. 函数返回两个数字相加的结果。
# 第二部分:使用 import 导入模块
# 1. 在本文件中使用 import calculator 导入模块。
# 2. 调用 calculator.add(10, 20)。
# 3. 输出格式为“计算结果30”。
# 第三部分:使用 from...import... 导入函数
# 1. 使用 from calculator import add 导入 add()。
# 2. 直接调用 add(5, 8)。
# 3. 输出格式为“新的计算结果13”。
# 第四部分:理解程序入口
# 1. 在 calculator.py 中定义 main() 函数。
# 2. main() 输出“正在测试计算模块。”。
# 3. 使用 if __name__ == "__main__": 判断后调用 main()。
# 4. 直接运行 calculator.py 时,应看到测试文字。
# 5. 运行 practice.py 时,不应自动看到测试文字。
# 第五部分:创建自己的包
# 1. 在当前课程目录创建 text_package 文件夹。
# 2. 在其中创建 __init__.py 和 text_tools.py。
# 3. 在 text_tools.py 中定义 make_title(text) 函数。
# 4. 函数返回 f"=== {text} ==="。
# 5. 在本文件中从 text_package.text_tools 导入 make_title。
# 6. 调用函数并输出,预期结果为“=== Python 学习 ===”。
# 完成后自查:
# 1. 是否理解一个 .py 文件可以作为模块;
# 2. 是否会使用 import 模块名;
# 3. 是否会使用 from 模块名 import 名称;
# 4. 是否知道导入模块时不会执行入口判断中的测试代码;
# 5. 是否能创建包含 __init__.py 的简单包;
# 6. 是否能从包中的模块导入函数。

View File

@@ -0,0 +1,4 @@
# 本课示例和练习运行时生成的数据。
# 这些内容可以重新生成,不需要纳入 Git 版本管理。
runtime_data/
practice_data/

View File

@@ -0,0 +1,405 @@
# 第 2-2 课:文件与目录操作
## 一、本课目标
完成本课后,你将能够:
1. 解释文件、目录和路径分别是什么;
2. 使用 `Path` 表示和组合路径;
3. 创建练习目录;
4. 安全地写入、追加和读取文本文件;
5. 检查路径是否存在,以及它是不是文件;
6. 遍历目录中的文件;
7. 说明文件操作可能带来的副作用。
## 二、前置知识
学习本课前,需要掌握:
- 字符串、变量和布尔值;
- 条件判断与循环;
- 函数、参数和返回值;
- 模块、导入和程序入口判断。
上一课学习了模块。本课将从 Python 标准库中导入 `pathlib` 模块提供的 `Path`
## 三、文件、目录和路径是什么
文件File是保存在计算机中的一份数据例如
- Python 程序 `practice.py`
- 文本文件 `learning_notes.txt`
- 图片文件 `photo.png`
目录Directory也常被称为文件夹用于组织文件和其他目录。
路径Path用于描述文件或目录在计算机中的位置。例如
```text
02_python进阶/2_2_文件与目录操作/runtime_data/learning_notes.txt
```
可以把路径理解为从一个位置找到目标文件所经过的路线。
## 四、为什么使用 `Path`
不同操作系统表示路径的方式可能不同。Windows 常见反斜杠 `\`,其他系统常见正斜杠 `/`。手工拼接路径容易写错。
`pathlib` 是 Python 标准库中的路径处理模块。`Path` 是它提供的路径对象:
```python
from pathlib import Path
lesson_dir = Path(__file__).parent
data_dir = lesson_dir / "runtime_data"
```
对象Object可以暂时理解为“同时保存数据和操作能力的值”。面向对象课程会详细讲解。
这里:
- `__file__` 是 Python 自动提供的特殊变量,表示当前文件的位置;
- `Path(__file__)` 把位置转换成路径对象;
- `.parent` 得到当前文件所在的目录;
- `/ "runtime_data"` 在原路径后面组合新的目录名。
这里的 `/` 不是数学除法。`Path` 对象把它设计成了清晰的路径组合写法。
## 五、相对路径与绝对路径
相对路径Relative Path表示相对于当前工作位置的路线
```text
runtime_data/learning_notes.txt
```
绝对路径Absolute Path从磁盘或系统根位置开始完整描述目标位置。在 Windows 中可能类似:
```text
F:\PyCharm\PythonLearn\02_python进阶\2_2_文件与目录操作
```
本课通过 `Path(__file__).parent` 取得课程目录。这样无论从项目根目录还是课程目录启动示例,数据都会写入本课自己的 `runtime_data`
## 六、创建目录
```python
data_dir.mkdir(parents=True, exist_ok=True)
```
`mkdir()` 表示创建目录:
- `parents=True`:需要时一并创建缺少的上级目录;
- `exist_ok=True`:目录已经存在时不报错。
如果没有 `exist_ok=True`,第二次运行程序时可能出现:
```text
FileExistsError
```
中文解释:程序想创建的文件或目录已经存在。
## 七、写入文本文件
```python
notes_file.write_text(
"第一条:学习使用 Path 表示路径。\n",
encoding="utf-8",
)
```
`write_text()` 会创建文件并写入文本。如果文件已经存在,它会覆盖原有内容。
覆盖意味着旧内容会被替换,可能难以恢复。因此:
- 练习时只操作专用数据目录;
- 写入前确认路径是否正确;
- 不要把重要文件路径交给练习程序;
- 中文文本明确使用 `encoding="utf-8"`
编码Encoding是文字与计算机数据之间的转换规则。UTF-8 是常用的文字编码,可以保存中文和多种语言。
字符串中的 `\n` 表示换行。
## 八、追加文本文件
覆盖写入会清空旧内容。希望在文件末尾增加内容时,可以使用追加模式:
```python
with notes_file.open("a", encoding="utf-8") as file:
file.write("第二条:学习读取和追加文件。\n")
```
打开模式File Mode`"a"` 中的字母来自 append表示追加。
`with` 语句会在代码块结束后帮助关闭文件。即使以后文件操作发生错误,也更容易正确释放文件资源。
本课先记住固定结构:
```python
with path.open("a", encoding="utf-8") as file:
file.write("需要追加的内容")
```
## 九、读取文本文件
```python
content = notes_file.read_text(encoding="utf-8")
print(content)
```
`read_text()` 会读取整个文本文件,并返回一个字符串。
如果文件不存在,可能出现:
```text
FileNotFoundError
```
中文解释Python 在指定路径没有找到需要读取的文件。
可以先检查文件是否存在:
```python
if notes_file.exists():
content = notes_file.read_text(encoding="utf-8")
```
## 十、检查路径
常用检查方法:
```python
path.exists()
path.is_file()
path.is_dir()
```
- `exists()`:路径是否存在;
- `is_file()`:路径是否存在并且是文件;
- `is_dir()`:路径是否存在并且是目录。
这些方法返回布尔值 `True``False`,可以与条件判断配合使用。
## 十一、遍历目录
```python
for path in data_dir.iterdir():
if path.is_file():
print(path.name)
```
`iterdir()` 会提供目录中的每一项。每一项仍然是 `Path` 对象:
- `path.name` 表示文件或目录的名称;
- `path.is_file()` 判断它是否是文件。
本课只遍历当前目录,不递归进入更深层目录。递归表示一个操作继续处理内部的子目录,属于后续扩展内容。
## 十二、示例文件与数据影响
本课文件结构:
```text
02_python进阶/2_2_文件与目录操作/
├── .gitignore
├── README.md
├── file_directory_example.py
└── practice.py
```
运行示例后会产生:
```text
runtime_data/
└── learning_notes.txt
```
运行练习后应产生:
```text
practice_data/
└── diary.txt
```
这两个数据目录都被本课 `.gitignore` 忽略,不会加入 Git。程序不会操作课程目录之外的文件。
每次运行完整示例时,`learning_notes.txt` 会先被写入初始内容,再追加第二条记录,因此结果不会无限重复增加。
## 十三、运行方法
在 PowerShell 中进入项目根目录:
```powershell
cd F:\PyCharm\PythonLearn
```
运行完整示例:
```powershell
python .\02_python进阶\2_2_文件与目录操作\file_directory_example.py
```
完成练习后运行:
```powershell
python .\02_python进阶\2_2_文件与目录操作\practice.py
```
## 十四、运行结果
完整示例的预期结果类似:
```text
数据目录已准备runtime_data
初始内容已写入learning_notes.txt
新的学习记录已追加。
学习记录内容:
第一条:学习使用 Path 表示路径。
第二条:学习读取和追加文件。
数据目录中的文件:
- learning_notes.txt
```
然后可以打开 `runtime_data/learning_notes.txt`,确认文件内容与终端输出一致。
## 十五、关键代码执行顺序
运行 `file_directory_example.py` 时:
1. 导入 `Path`
2. 根据当前文件位置准备课程目录、数据目录和文件路径;
3. 定义文件操作函数;
4. 入口判断成立,调用 `main()`
5. 创建 `runtime_data`
6. 覆盖写入初始记录;
7. 在文件末尾追加一条记录;
8. 读取并输出完整内容;
9. 遍历数据目录并输出文件名。
先创建目录再写文件非常重要。目录不存在时,直接写入内部文件会失败。
## 十六、常见错误
### 16.1 手工拼接路径
不推荐:
```python
file_path = lesson_dir + "/runtime_data/notes.txt"
```
`lesson_dir``Path` 对象,不能直接与普通字符串这样相加。使用:
```python
file_path = lesson_dir / "runtime_data" / "notes.txt"
```
### 16.2 忘记创建目录
`runtime_data` 不存在时直接写入内部文件,会出现 `FileNotFoundError`。应先调用 `mkdir()`
### 16.3 忘记指定中文编码
读取或写入中文时未指定 UTF-8可能出现乱码或编码错误。请在读写两端都使用 `encoding="utf-8"`
### 16.4 混淆覆盖和追加
- `write_text()` 会覆盖原内容;
- `open("a")` 会在末尾追加内容。
操作重要文件前必须确认自己需要哪一种行为。
### 16.5 忘记关闭文件
手动调用 `open()` 后如果忘记关闭文件,可能造成资源占用。本课使用 `with` 自动管理文件。
### 16.6 路径指向项目外部
练习时不要使用系统目录、桌面文件或其他项目文件。把所有练习数据限制在本课的 `practice_data` 中。
## 十七、课堂练习
打开 `practice.py`,依次完成:
1. 准备练习目录和日记文件路径;
2. 创建 `practice_data`
3. 写入第一条日记;
4. 追加第二条日记;
5. 读取并输出完整内容;
6. 检查文件是否存在并遍历目录。
每完成一部分就运行一次。不要直接复制参考答案。
## 十八、参考答案
请先独立完成练习,再展开查看。
<details>
<summary>查看参考答案</summary>
```python
from pathlib import Path
lesson_dir = Path(__file__).parent
practice_dir = lesson_dir / "practice_data"
diary_file = practice_dir / "diary.txt"
practice_dir.mkdir(parents=True, exist_ok=True)
print("练习目录已准备。")
first_entry = "今天学习了文件与目录。\n"
diary_file.write_text(first_entry, encoding="utf-8")
print("日记已写入。")
with diary_file.open("a", encoding="utf-8") as file:
file.write("我会使用 Path 处理路径。\n")
print("日记已追加。")
content = diary_file.read_text(encoding="utf-8")
print("日记内容:")
print(content, end="")
if diary_file.exists():
print("日记文件存在。")
print("练习目录中的文件:")
for path in practice_dir.iterdir():
if path.is_file():
print(path.name)
```
</details>
## 十九、本课小结
- 文件保存数据,目录用于组织文件,路径描述它们的位置;
- `Path` 可以清晰地表示和组合路径;
- `mkdir()` 可以创建目录;
- `write_text()` 可以写入文本,但会覆盖原内容;
- `open("a")` 可以追加内容;
- `read_text()` 可以读取整个文本文件;
- `with` 可以帮助正确关闭文件;
- `exists()``is_file()``is_dir()` 可以检查路径;
- `iterdir()` 可以遍历目录;
- 文件操作存在副作用,必须限制操作范围并确认目标路径。
## 二十、验收标准
完成本课时,应满足:
- 可以解释文件、目录、相对路径和绝对路径;
- 可以使用 `Path(__file__).parent` 定位当前课程目录;
- 可以使用 `/` 组合 `Path` 路径;
- 可以创建已经存在也不会报错的目录;
- 可以正确写入、追加和读取中文文本;
- 可以解释覆盖写入与追加写入的区别;
- 可以使用 `with` 打开文件;
- 可以检查路径并遍历目录中的文件;
- 练习数据只出现在 `practice_data` 中;
- 运行两次练习,程序都不会崩溃;
- 最终日记内容不会因为重复运行而无限增加。

View File

@@ -0,0 +1,71 @@
# 第 2-2 课完整示例:文件与目录操作
#
# 本程序只会在当前课程目录的 runtime_data 文件夹中创建和修改文件。
# runtime_data 已被本课的 .gitignore 忽略,不会污染 Git 变更记录。
from pathlib import Path
# __file__ 表示当前 Python 文件的位置。
# parent 表示当前文件所在的目录。
LESSON_DIR = Path(__file__).parent
DATA_DIR = LESSON_DIR / "runtime_data"
NOTES_FILE = DATA_DIR / "learning_notes.txt"
def create_data_directory():
"""创建保存示例数据的目录。"""
# parents=True 表示需要时一并创建上级目录。
# exist_ok=True 表示目录已经存在时不报错。
DATA_DIR.mkdir(parents=True, exist_ok=True)
print(f"数据目录已准备:{DATA_DIR.name}")
def write_initial_notes():
"""写入初始学习记录。"""
notes = "第一条:学习使用 Path 表示路径。\n"
# write_text() 会覆盖文件原有内容。
# encoding="utf-8" 可以正确保存中文。
NOTES_FILE.write_text(notes, encoding="utf-8")
print(f"初始内容已写入:{NOTES_FILE.name}")
def append_note():
"""在文件末尾追加一条学习记录。"""
# open() 打开文件后,需要在操作结束时关闭文件。
# with 语句会帮助我们自动关闭文件。
# 模式 "a" 表示追加,不会清空原有内容。
with NOTES_FILE.open("a", encoding="utf-8") as file:
file.write("第二条:学习读取和追加文件。\n")
print("新的学习记录已追加。")
def read_notes():
"""读取并输出全部学习记录。"""
content = NOTES_FILE.read_text(encoding="utf-8")
print("学习记录内容:")
print(content, end="")
def show_directory_contents():
"""遍历并显示数据目录中的内容。"""
print("数据目录中的文件:")
for path in DATA_DIR.iterdir():
if path.is_file():
print(f"- {path.name}")
def main():
"""按照安全顺序运行文件与目录示例。"""
create_data_directory()
write_initial_notes()
append_note()
read_notes()
show_directory_contents()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,45 @@
# 第 2-2 课课堂练习:文件与目录操作
#
# 请先阅读讲义并运行完整示例,再按照顺序完成练习。
# 所有练习数据只能保存在当前课程目录的 practice_data 文件夹中。
# 不要使用本课尚未要求的删除操作,也不要修改项目中的其他文件。
# 第一部分:准备路径
# 1. 从 pathlib 导入 Path。
# 2. 使用 Path(__file__).parent 得到当前课程目录。
# 3. 准备 practice_data 目录路径。
# 4. 准备 practice_data/diary.txt 文件路径。
# 第二部分:创建目录
# 1. 使用 mkdir(parents=True, exist_ok=True) 创建 practice_data。
# 2. 输出“练习目录已准备。”。
# 3. 连续运行两次,确认第二次运行不会报错。
# 第三部分:写入文件
# 1. 准备字符串“今天学习了文件与目录。\n”。
# 2. 使用 write_text() 写入 diary.txt。
# 3. 明确指定 encoding="utf-8"。
# 4. 输出“日记已写入。”。
# 第四部分:追加内容
# 1. 使用 with 和 open("a", encoding="utf-8") 打开 diary.txt。
# 2. 追加“我会使用 Path 处理路径。\n”。
# 3. 输出“日记已追加。”。
# 第五部分:读取内容
# 1. 使用 read_text(encoding="utf-8") 读取 diary.txt。
# 2. 输出标题“日记内容:”。
# 3. 输出读取到的全部内容。
# 第六部分:检查和遍历
# 1. 使用 exists() 检查 diary.txt 是否存在。
# 2. 存在时输出“日记文件存在。”。
# 3. 使用 iterdir() 遍历 practice_data。
# 4. 只输出文件,并通过 name 属性显示文件名。
# 完成后自查:
# 1. 是否始终使用 Path 组合路径,而不是手工拼接斜杠;
# 2. 是否把练习数据限制在 practice_data 中;
# 3. 写入和读取中文时是否指定 utf-8
# 4. 是否知道 write_text() 会覆盖原内容;
# 5. 是否知道追加模式 "a" 不会清空原内容;
# 6. 是否能解释 with 为什么可以帮助关闭文件;
# 7. 是否能使用 exists()、is_file() 和 iterdir()。

View File

@@ -188,13 +188,13 @@ Python/
## 当前学习进度
- 当前阶段:第阶段——Python 基础语法
- 当前课程:`1_14_python基础综合项目`
- 当前状态:第一阶段 Python 基础课程已完成
- 已完成课程:`1_1_hello_world``1_14_python基础综合项目`
- 学习中的课程:暂无
- 已创建课程目录:`01_python基础/1_1_hello_world/``01_python基础/1_14_python基础综合项目/`
- 下一步:进入第二阶段 Python 进阶,学习模块与包
- 当前阶段:第阶段——Python 进阶
- 当前课程:`2_2_文件与目录操作`
- 当前状态:正在学习文件与目录操作
- 已完成课程:`1_1_hello_world``1_14_python基础综合项目`,以及 `2_1_模块与包`
- 学习中的课程:`2_2_文件与目录操作`
- 已创建课程目录:第一阶段全部课程,以及 `02_python进阶/2_1_模块与包/``02_python进阶/2_2_文件与目录操作/`
- 下一步:完成文件与目录操作练习,然后学习异常处理
## 建议环境
@@ -209,10 +209,12 @@ Python/
## 下一步
第一阶段 Python 基础课程已经完成。下一课将学习:
上一课“模块与包”已经完成。当前正在学习文件与目录操作,本课将学习:
1. 模块是什么,以及为什么要拆分文件
2. 使用 `import` 导入模块
3. 使用 `from...import...` 导入指定内容
4. 理解 `__name__ == "__main__"`
5. 创建和使用自己的模块与包。
1. 文件、目录和路径的基本含义
2. 使用 `Path` 表示和组合路径
3. 创建练习目录
4. 写入、追加和读取文本文件
5. 检查路径并遍历目录内容。
完成本课练习并确认继续后,下一课将学习异常处理。