5. 关于with
- 概述:Python 中的with主要用于管理程序中“需要成对出现的操作”,例如:
🔸上锁 / 解锁
🔸打开 / 关闭
🔸借用 / 归还
- 使用with的目标:编码者只管做具体的事,“进入”和“离开”的事,让 Python 自动处理。
- 语法格式:
with 能得到一个上下文管理器的表达式 as 变量:
具体的事1
具体的事2
具体的事3
- 上下文管理器协议:
- __enter__ 方法:with中的代码执行【之前】调用,其返回值会赋值给as后的变量。
- __exit__ 方法:with中的代码执行【结束后】调用(无论是with中否出现异常都会调用)。
- 测试代码:
# 定义一个 Person 类,让其实例对象遵循:上下文管理器协议
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
print(f'我叫{self.name},年龄是{self.age}')
def __enter__(self):
print('-----我是进入的逻辑-----')
return self
# 当 with 中的代码发生异常时,__exit__ 方法的返回值规则如下:
# 🔸返回“真”:表示异常【已经】被处理,异常【不会】被继续抛出。
# 🔸返回“假”:表示异常【没有】被处理,异常【会】被继续抛出。
def __exit__(self, exc_type, exc_val, exc_tb):
print('-----我是离开的逻辑-----')
# exc_type : 异常类型
# exc_val : 异常对象
# exc_tb : 异常追踪信息
if exc_type:
print(f'异常类型:{exc_type}')
print(f'异常对象:{exc_val}')
print(f'异常追踪信息:{exc_tb}')
return True
# 1.计算 with 后面的表达式,得到一个『上下文管理器』。
# 2.调用『上下文管理器』的 __enter__() 方法,并将其返回值赋给 as 后面的变量。
# 3.执行 with 所管理的代码。
# 4.无论代 with 中的代码,是正常结束,还是发生异常,都会自动调用『上下文管理器』的 __exit__ 方法。
with Person('张三', 18) as p1:
p1.speak()
# p1.study()
print(666)
6. 写入文件
1️⃣w模式
- 概述:w模式是写入模式,写入前会先截断文件(清空文件)。
- 代码:
with open('b.txt', 'wt', encoding='utf-8') as file:
file.write('你好')
2️⃣x模式
- 概述:x模式是排它性创建,如果文件已存在,则创建失败。
- 代码:
with open('demo.txt', 'xt', encoding='utf-8') as file:
file.write('你好')
3️⃣a模式
- 概述:打开文件用于写入,如果文件存在,则在文件末尾追加内容。
- 代码:
with open('a.txt', 'at', encoding='utf-8') as file:
file.write('你好')
7. flush方法
- 概述:Python 写入文件时,并不是每写一次就立刻落盘,而是:先写到“缓冲区”里。
- flush方法:把缓冲区中的数据,立刻写入到文件中。
- 测试代码:
import time
with open('demo.txt', 'at', encoding='utf-8') as file:
file.write('你好1')
file.write('你好2')
file.flush()
time.sleep(10000)
file.write('你好3')
file.write('你好4')
8. 组合模式
1️⃣rt+模式
- 概述:r模式可以读取,+模式可以更新(读取或写入),所以rt+模式可读可写。
- 注意:r模式打开文件后,文件指针在起始位置。
- 备注:由于t是默认值,所以rt+中的t可以省略。
- 代码:
with open('a.txt', 'rt+', encoding='utf-8') as file:
# seek(offset, whence)方法:用于改变文件对象指针的位置,参数说明如下:
# offset:偏移量,要移动多少距离
# whence:参考点,从哪里开始计算偏移,有三种取值:
# 0:从文件开头计算(默认值)
# 1:从当前位置计算
# 2:从文件末尾计算
# 注意:在文本模式下,不要随意去定位中文字符位置,否则可能破坏文件编码。
file.seek(0, 0)
file.write('你好')
2️⃣wt+模式
- 概述:w模式可以写入,+模式可以用于更新(读取或写入),所以wt+模式可读可写。
- 注意:w模式打开文件后,文件指针在起始位置,但write方法执行完后,指针在文件结束位置。
- 备注:由于t是默认值,所以wt+中的t可以省略。
- 代码:
with open('a.txt', 'wt+', encoding='utf-8') as file:
file.write('你好')
file.seek(0, 0)
result = file.read()
print(result)
3️⃣xt+模式
- 概述:x模式可以写入,+模式可以用于更新(读取或写入),所以xt+模式可读可写。
- 注意:x模式打开文件后,文件指针在起始位置。
- 备注:由于t是默认值,所以xt+中的t可以省略。
- 代码:
with open('demo3.txt', 'xt+', encoding='utf-8') as file:
file.write('你好')
file.seek(0, 0)
result = file.read()
print(result)
3️⃣at+模式
- 概述:a模式可以追加内容,+模式可以用于更新(读取或写入),所以at+模式可读可写。
- 注意:a模式打开文件后,文件指针在结束位置。
- 备注:由于t是默认值,所以at+中的t可以省略。
- 代码:
with open('a.txt', 'at+', encoding='utf-8') as file:
file.write('你好')
file.seek(0, 0)
result = file.read()
print(result)
9. 目录操作
Python 中常见的目录操作如下:
import os
import shutil
# 1️⃣os.mkdir(path):创建“单级”目录(如果目录已经存在,则会抛出异常)
os.mkdir('D:/demo')
# 2️⃣os.makedirs(path):创建“多级”目录(如果路径中的所有目录都已经存在,则会抛出异常)
os.makedirs('D:/demo/aa/bb')
# 3️⃣os.rmdir(path):删除空目录(如果目录不存在,或目录非空,都会抛出异常)
os.rmdir('D:/demo/aa/bb')
# 4️⃣os.removedirs(path):递归删除空目录,在成功删除末尾一级目录后,会“向上”尝试把父级目录也删除
# (直到父目录不是空目录)
os.removedirs('D:/demo/aa/bb')
# 5️⃣os.path.exists(path):判断路径是否存在(文件/目录都算)
result = os.path.exists('D:/demo/aa/bb')
print(result)
# 6️⃣os.path.isdir(path):用于判断路径,具体规则如下:
# 1.路径不存在 ==================> 返回 False
# 2.路径存在,但指向的是文件 =====> 返回 False
# 3.路径存在,并且是目录 =======> 返回 True
result = os.path.isdir('D:/demo/aa/bb')
print(result)
# 7️⃣os.path.isfile(path):判断是否为文件
result = os.path.isfile('D:/demo/aa/bb')
print(result)
# 8️⃣os.scandir(path):扫描指定目录
result = os.scandir('D:/demo')
for item in result:
print('目录' if item.is_dir() else '文件', item.name)
# 9️⃣os.walk(path):按层级,递归地遍历指定目录下,所有的子目录和文件
result = os.walk('D:/demo')
for item in result:
print(item)
# ⚠️危险操作:删除有内容的目录
shutil.rmtree('D:/demo')
10. 两个小练习
练习 1:将一个二进制文件复制到指定位置。
import os
# 源文件
source = 'music.mp3'
# 目标目录
target = 'D:/media'
# 如果目标目录不存在,那就去创建
if not os.path.isdir(target):
os.makedirs(target)
with open(source, 'rb') as f1, open(target + '/' + 'my_music.mp3', 'wb') as f2:
while True:
# 每次只读取1KB
data = f1.read(1024)
# 如果文件读取完毕了,就跳出循环
if not data:
break
# 向目标文件中写入数据
f2.write(data)
print('复制完毕')
练习 2:日志记录,需求如下:
- 用户输入用户名和密码后,程序进行校验:
- 用户名不存在,提示“用户名未注册”,并记录日志。
- 用户名存在,但密码错误,提示“密码错误”,并记录日志。
- 用户名和密码均正确,提示“登录成功”,并记录日志。
import time
# 准备一些用户
users = {
'张三': '123456',
'李四': '888888',
'王五': 'abc123'
}
# 提示输入信息
username = input('请输入用户名:')
password = input('请输入密码:')
# 获取当前的时间
now = time.strftime('%Y-%m-%d %H:%M:%S')
# 如果用户名不在users中
if username not in users:
print('用户名未注册')
with open('log.txt', 'at', encoding='utf-8') as file:
file.write(f'{now} {username} 登录失败(用户未注册)n')
# 如果密码不正确
elif users[username] != password:
print('密码不正确')
with open('log.txt', 'at', encoding='utf-8') as file:
file.write(f'{now} {username} 密码错误 n')
# 登录成功
else:
print('登录成功!')
with open('log.txt', 'at', encoding='utf-8') as file:
file.write(f'{now} {username} 登录成功 n')

AI项目博客






