- 掌握文件指针,理解指针概念
- 异常捕获 能够看懂各类异常
- 常用推导式
- 这里代码有优化 推导式行列转换
今日习题
# 1.打开文件的两种方式
# 2.操作文件的几种方式
# 3.操作文件的几种方法
# 4.什么是字符编码
# 5.字符编码的发展过程
# 6.如何进行编码和解码
昨日内容回顾
# 【一】可变数据类型和不可变数据类型
# 区分依据是根据 当前数据修改后的内存地址变化和不变化来区分
# 不可变数据类型:整数和浮点数 、 字符串 、 布尔类型 、 元组
# 可变数据类型 列表 集合 字典
# Python是值传递还是引用传递
# 引用传递就是可变数据类型
# 值传递就是不可变数据类型
# 【二】垃圾回收机制
# 当我们在程序运行过程中会有一些数据是没有用的,但是你不会自己主动删除这部分数据
# 这部分数据乐队越多 导致内存占用越来越多 导致你的内存溢出
# 为了解决上述问题 于是 Python 解释器自带了一个垃圾回收机制
# 垃圾回收机制又叫GC机制
# 引用计数 标记清除 分代回收
# 【1】引用计数
# 当一个变量值被一个变量名引用的时候自己的计数器就会 + 1
# 当这个变量值没有被其他变量引用的时候 计数器就会变为 0
# 当前值不再被当前程序锁需要 就是垃圾
# 如果垃圾立即回收 而下一次还要使用 就会造成程序崩溃
# 【2】标记清除
# 每个一段时间去程序中扫描产生的垃圾数据
# 如果频繁的扫描到某个数据 那就给他打上标记
# 当标记到达一定次数的时候就会给他重新各类
# 【3】分代回收
# 对上面分好类的垃圾进行清除
# 清除最后一次扫描次数最多的垃圾
# 新生代 : 大概个10min扫描一次 积累100次就给他提升至青春代
# 青春代 : 大概个20min扫描一次 积累200次就给他提升至老年代
# 老年代 : 大概个30min扫描一次 积累300次就将其清除
# 【三】深浅拷贝
# 借助内置模块 copy
# 浅拷贝:将原本的对象复制成一个新的对象,但是新的对象共享原对象本身的关联关系 copy
# 当列表中嵌了一个列表的时候 ,修改原本的对象中的列表中的列表的时候 , 浅拷贝 出来的对象中的列表中的列表也会产生影响
# 深拷贝 : 将原本的对象复制成一个新的对象,但是新的对象会递归的复制原本对象中的关联关系从而变成独立的对象 copy.deepcopy
# 当列表中嵌了一个列表的时候 ,修改原本的对象中的列表中的列表的时候 , 深拷贝 出来的对象中的列表中的列表不会产生影响
# 【四】字符编码
# 字符编码就是将人类可以识别的字符转换成计算机可以识别的二进制数据 或者 将计算机可以识别的二进制数据转换成人类可以识别的字符
# 字符编码的发展史 : 一家独大 诸侯割据 一统天下
# 【1】一家独大
# 美国人发明计算机 于是就想让计算机可以识别英文 于是就有了英文和二进制数据之间的映射表 ASCII码表
# 【2】诸侯割据
# 随着计算机的普及 很多国家都会有计算机用 每一个国家都想有自己国家的字符和二进制数据之间的映射关系
# 于是就诞生了每个国家自己的编码表 gbk shift_gis 等等
# 【3】一统天下
# 当一个别过的程序员想要开发不同国家的代码程序的时候就需要下载其他国家的编码表
# 于是为了解决需要很多编码表的问题 于是就出现了unicode编码表 万国码表
# 有了 unicode 表以后存储数据的过程就变成了
# 英文字符 ---> unicode 表 ---> ascii 码表找数据 ---> 存档
# 中文字符 ---> unicode 表 ---> gbk 码表找数据 ---> 存档
# 于是就诞生了一个统一的二进制数据编码格式 utf-8
# 英文字符 ---> unicode 表 ---> utf-8 编码转为二进制 ---> 存档
# 中文字符 ---> unicode 表 ---> utf-8 编码转为二进制 ---> 存档
# 【4】编码和解码 的过程
# 编码 字符串转二进制 需要用 encode(指定编码格式默认是 utf-8 )
# 解码 二进制转字符串 需要用 decode(指定解码格式默认是 utf-8 )
# 在以前的 2.x 版本的 Python解释器上 是没有默认编码格式的
# 在以前需要再你的 Python 文件的 第一行加入一个指定的编码格式 语句
# -*- coding: UTF-8 -*-
# 【五】文件操作
# 【1】打开文件的两种方式
# 方式一:将文件打开赋给句柄 然后操作文件 关闭文件
'''
fp = open(file="文件路径", mode="打开模式", encoding="编码格式")
fp.write()
fp.close()
'''
'''
fp = open("1.text","w",encoding="utf-8")
fp.write("666")
fp.close()
'''
# 方式二:Python提供了自动回收资源的打开方式
'''
with open("1.text", "w", encoding="utf-8") as fp:
fp.write('666')
'''
# 【2】文件操作方式
# r 模式 read 模式 :文件只读模式
# 文件不存在就会报错
# w 模式 write 模式 :文件只写模式
# 覆盖写 在每一次打开文件写入数据的时候会默认清除掉原本的内容然后向其中写入信的内容
# 文件不存在的时候会创建新文件然后写入内容
# 在with语句下只要不走到 with 外边就能连续写入数据
# a 模式 append 模式 :文件只追加模式
# 追加写 在每一次打开文件写入数据的时候会默认追加到文件末尾
# 文件不存在的时候会创建新文件然后写入内容
# 在with语句下只要不走到 with 外边就能连续写入数据
# 【3】拓展模式
# r+ / w+ / a+ : 让原本的只写变成既能读又能写
# wb / rb : 处理二进制数据的
# 【4】文件的操作方法
# r 模式:
# f.read() 一次性将文件内容全部读出
# f.readline() 一次性只读一行内容
# f.readlines() 一次性读取所有行内容并且将每一行作为列表中的每一个元素
# f.readable() 判断文件是否可读
# w 模式
# f.write() 一次性将数据写入文件
# f.writelines(可迭代类型,放列表) 先将列表中的所有数据拼接到一起 拼接好了以后再一次性写入
'''
user_data = {
"username": "dream",
"password": "521",
"age": 18,
"gender": "男",
True: "ok"
}
# value_list = []
data = ''
for value in user_data.values():
data += str(value) + '|'
print(data)
with open("user_data.text", "w", encoding="utf-8") as fp:
# fp.writelines('|'.join(value_list))
# fp.writelines(user_data)
fp.write(data)
'''
# with open("user_data.text", "r") as fp:
# for i in fp:
# print(i) # dream|521|18|男|ok|
# # print( i.split("|").pop())
# # list_data = i.split("|")
# # list_data.pop()
# a, b, c, d, e, _ = i.split("|")
# print(a, b, c, d, e)
user_data = {
"dream": {
"username": "dream",
"password": "521",
"age": 18,
"gender": "男",
True: "ok"
},
"hope": {
"username": "hope",
"password": "521",
"age": 18,
"gender": "男",
True: "ok"
}
}
# user_list = []
# for user_info in user_data.values():
# data = ''
# for value in user_info.values():
# data += str(value) + '|'
# user_list.append(data + '\n')
#
# print(user_list)
# for user_info in user_data.values():
# data = '|'.join([str(value) for value in user_info.values()])
# print(data)
#
# data = ['|'.join([str(value) for value in user_info.values()]) for user_info in user_data.values()]
#
# print(data)
【一】控制文件内指针移动
【1】前言
with open("1.text",'r',encoding="utf-8") as fp:
data = fp.read().split(" ")
data.insert(1,"dear")
data = ' '.join(data)
print(data)
with open("2.text",'w',encoding="utf-8") as fp:
fp.write(data)
【2】read的参数
with open("2.text", 'r', encoding="utf-8") as fp:
# fp.read(数字)
# read 里面的数字可以控制当前 读取的内容的字符个数 并且 读是从头开始读的
# read(数字) 数字默认是 -1 从头读到尾
data = fp.read(-1)
print(data)
【3】seek移动指针
with open("2.text", 'r+', encoding="utf-8") as fp:
# tell 查看当前指针所在的字节位置
# print(fp.tell()) # 0
# fp.write('Hello 蚩梦')
# data = fp.read(-1)
# print(data) # Hello dear 蚩梦
# 一个中文占 3 个字节
# print(fp.tell()) # 17
# seek 方法可以控制指针移动
# offset 移动几个字节
# whence 移动模式
# 0 : 默认的模式,按照文件开头作为参照向后移动指定字节数
# 1 : 按照当前所在位置作为参照向后移动指定字节数
# 2 : 按照文件末尾作为参照向后移动指定字节数
# print(fp.tell())
# # fp.seek(4, 0)
# print(fp.tell())
# 1 只能用在二进制数据上 ,文本数据不支持 相对移动
# fp.seek(2, 1)
# fp.seek(0, 2)
# print(fp.tell()) # 17
# fp.write("11111")
# 控制光标移动到指定字节位置的时候写入数据是从当前字节位置覆盖写入内容
# 一个中文占3个字节,如果写入的时候恰巧是中文并且写入的不够三个字节就会导致文件出现乱码
fp.seek(6, 0)
# print(fp.read(-1))
# Hello 蚩梦
# dear --=> 文件变成乱码
fp.write("dea")
【4】小结
# seek
# seek(字节数,模式)
# 0 : 默认的模式,按照文件开头作为参照向后移动指定字节数
# 1 : 按照当前所在位置作为参照向后移动指定字节数(不能用于文本数据而是要用于二进制数据)
# 2 : 按照文件末尾作为参照向后移动指定字节数
# 控制光标移动到指定字节位置的时候 如果遇到中文一定要留意是 3个字节一个中文
# 控制光标移动到指定字节位置的时候写入数据是从当前字节位置覆盖写入内容
# a 模式的原理就是先将 光标移动到最后的位置 然后继续向下写内容
# w 模式 用seek 移动到结尾和上面的a模式是一样的效果
'''
with open("自愿上班.jpeg", 'rb') as fp:
fp.seek(5, 0)
print(fp.tell())
fp.seek(5, 1)
print(fp.tell())
'''
【二】异常捕获
# 【一】什么是异常
# 程序在运行过程中遇到的报错,导致程序崩溃的代码就是异常
# 我们在程序运行过程中 不应该让程序报错 或者 在程序报错之后应该立马通知开发者
# 并且有相应的异常重启机制
# 【二】异常捕获
# 内建异常:Python解释器自带的异常捕获机制
# ValueError: invalid literal for int() with base 10: 'a'
# 自定义异常:我们自己主动抛出的异常
"""
print(1)
print(2)
raise ValueError("不能打印3")
print(4)
"""
# 【三】内建异常
# BaseException: 所有异常的基类
# ● SystemExit:解释器请求退出
# ● KeyboardInterrupt:用户中断执行(通常是输入^C)
# ● Exception:常规错误的基类
# ● StopIteration:迭代器没有更多的值
# ● GeneratorExit:生成器(generator)发生异常来通知退出
# ● StandardError:所有的内建标准异常的基类
# ● ArithmeticError:所有数值计算错误的基类
# ● FloatingPointError:浮点计算错误
# ● OverflowError:数值运算超出最大限制
# ● ZeroDivisionError:除(或取模)零 (所有数据类型)
# ● AssertionError:断言语句失败
# ● AttributeError:对象没有这个属性
# ● EOFError:没有内建输入,到达EOF 标记
# ● EnvironmentError:操作系统错误的基类
# ● IOError:输入/输出操作失败
# ● OSError:操作系统错误
# ● WindowsError:系统调用失败
# ● ImportError:导入模块/对象失败
# ● LookupError:无效数据查询的基类
# ● IndexError:序列中没有此索引(index)
# ● KeyError:映射中没有这个键
# ● MemoryError:内存溢出错误(对于Python 解释器不是致命的)
# ● NameError:未声明/初始化对象 (没有属性)
# ● UnboundLocalError:访问未初始化的本地变量
# ● ReferenceError:弱引用(Weak reference)试图访问已经垃圾回收了的对象
# ● RuntimeError:一般的运行时错误
# ● NotImplementedError:尚未实现的方法
# ● SyntaxError:Python 语法错误
# ● IndentationError:缩进错误
# ● TabError:Tab 和空格混用
# ● SystemError:一般的解释器系统错误
# ● TypeError:对类型无效的操作
# ● ValueError:传入无效的参数
# ● UnicodeError:Unicode 相关的错误
# ● UnicodeDecodeError:Unicode 解码时的错误
# ● UnicodeEncodeError:Unicode 编码时错误
# ● UnicodeTranslateError:Unicode 转换时错误
# print(1 / 0) # ZeroDivisionError: division by zero
# 【三】警告异常
# Warning(警告的基类)
# ● DeprecationWarning:关于被弃用的特征的警告
# ● FutureWarning:关于构造将来语义会有改变的警告
# ● OverflowWarning:旧的关于自动提升为长整型(long)的警告
# ● PendingDeprecationWarning:关于特性将会被废弃的警告
# ● RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
# ● SyntaxWarning:可疑的语法的警告
# ● UserWarning:用户代码生成的警告
# 【四】如何主动抛出异常
# 借助关键字 raise
# 语法 raise [Exception [, args [, traceback]]]
'''
for i in range(10):
if i == 2:
raise ValueError("参数不能为2")
'''
# 【五】主动捕获异常
# 【1】不带异常信息
'''
try:
# 正常执行可能会发生错误的代码
int("a")
except:
# 异常处理机制
print(f"发生异常了")
...
'''
# 【2】只有单一的异常信息
'''
try:
# 正常执行可能会发生错误的代码
# int("a")
print(1 / 0)
# 放指定的异常类型 当上面的代码遇到指定的错误的时候才会被捕获到
except ValueError:
# 异常处理机制
print(f"发生异常了")
...
'''
# 【3】捕获多个异常信息
'''
try:
# 正常执行可能会发生错误的代码
print(1 / 0)
int("a")
# 放了多个不同的异常类型 并且将异常信息赋给 变量 e
except (ValueError, ZeroDivisionError) as e:
# 在处理异常的时候可以通过变量e查看到当前的异常类型和异常信息
# 异常处理机制
# 发生异常了 invalid literal for int() with base 10: 'a'
# 发生异常了 division by zero
print(f"发生异常了 {e}")
...
'''
# 【4】捕获所有异常信息
'''
try:
# 正常执行可能会发生错误的代码
# print(1 / 0)
int("a")
# print(1)
# Exception 捕获所有异常类型
except Exception as e:
# 在处理异常的时候可以通过变量e查看到当前的异常类型和异常信息
# 异常处理机制
print(f"发生异常了 {e}")
...
# 当代码没有抛出异常时 , 结束正常代码会自动进入到 else 语句中
else:
print(f"当前走入到 else 中")
# 不管代码抛出还是不抛出异常都会走入到 finally 当中
finally:
print(f"当前走入到 finally 中")
'''
# 【assert关键】
# 断言
# 当在程序中遇到某个条件为真的时候会抛出异常
# 在某个功能里面必须传入某个参数的时候 如果没有传入就可以抛出 assert 异常
'''
for i in range(10):
# if i == 2:
# raise ValueError("不能为2")
# assert 为真的判断条件,"异常信息"
# 一般用在源码中
assert i == 2, "不能为2"
'''
【三】生成式
# 【一】列表推导式
# 语法 [表达式 for 变量名 in 可迭代类型 if 条件]
# 为了简洁代码
# 【1】构建一个列表
'''
num_list = []
for i in range(10):
num_list.append(i)
print(num_list)
'''
'''
num_list = [i for i in range(10)]
print(num_list)
'''
# 【2】生成一个 从 0 -10 的数字的平方的列表
'''
num_list = [i ** 2 for i in range(10)]
print(num_list)
'''
'''
num_list = [i.upper() for i in "dream"]
print(num_list)
'''
# 【3】嵌套循环
num_one = [1, 2, 3]
num_two = [4, 5, 6]
'''
res_list = []
for i in num_one:
for j in num_two:
res = i * j
res_list.append(res)
print(res_list)
'''
'''
res_list = [i * j for i in num_one for j in num_two]
print(res_list)
'''
'''
res_list = [num_one[i] * num_two[i] for i in range(len(num_one))]
print(res_list)
'''
# 【4】行列转换
'''
python
复制下载
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
# 获取原矩阵的行数和列数
rows = len(matrix) # 3
cols = len(matrix[0]) # 4
# 创建转置后的矩阵:cols 行,每行是一个空列表
transposed = [[] for _ in range(cols)] # 得到 [[], [], [], []]
# 外层循环遍历原矩阵的行
for i in range(rows):
# 内层循环遍历原矩阵的列
for j in range(cols):
# 将原矩阵 [i][j] 元素添加到转置矩阵的第 j 行(即原第 j 列)
transposed[j].append(matrix[i][j])
print(transposed)
'''
# 【5】加入判断条件
'''
num_list = [1, 2, 3, 4, 5]
num_list_new = []
for i in num_list:
if i % 2 == 0:
num_list_new.append(i)
print(num_list_new)
print([i for i in num_list if i % 2 == 0])
'''
# 【二】字典生成式
# 语法 {变量1:变量2 for 变量1 in 可迭代对象: for 变量2 in 可迭代对象 if 表达式}
my_tuple_list = [('name', '橡皮擦'), ('age', 18), ('class', 'no1'), ('like', 'python')]
data_dict = {}
for line in my_tuple_list:
# line = ('name', '橡皮擦')
key, value = line
data_dict[key] = value
print(data_dict)
print({key: value for key, value in my_tuple_list})
# 【三】元组生成式
num = (i for i in range(10) if i % 2 == 0)
print([i for i in range(10) if i % 2 == 0])
# 生成器对象
print(list((i for i in range(10) if i % 2 == 0))) # <generator object <genexpr> at 0x106c3b4c0>
【四】昨日作业
# 用列表和字典做的多用户登录和注册
# 改成用文件做多用户登录和注册
# 规定保存的数据格式
# username|password|age|gender|role
# dream|521|18|male|admin
while True:
menu = '''
+++++++ 功能菜单 ++++++
1. 注册
2. 登陆
'''
# 判断当前用户是否存在
try:
user_data = {}
with open("user_data.text", 'r', encoding="utf-8") as fp:
for line in fp:
username, password, age, gender, role = line.strip().split('|')
user_data[username] = {
"username": username,
"password": password,
"age": age,
"gender": gender,
"role": role
}
except Exception as e:
user_data = {}
func_id = input("输入功能ID :>>>> ").strip()
if not func_id.isdigit():
print(f"当前ID非法")
continue
func_id = int(func_id)
if func_id not in [1, 2]:
print(f"功能ID不存在")
continue
if func_id == 1:
print(f"欢迎来到注册功能")
username = input("请输入用户名 :>>>> ").strip()
password = input("请输入密码 :>>>> ").strip()
age = input("请输入年龄 :>>>> ").strip()
gender = input("请输入性别(0 女 / 1 男) :>>>> ").strip()
if username == "dream" and password == "521":
role = "admin"
else:
role = "user"
print(user_data)
print(username)
user_info = user_data.get(username)
if user_info:
print(f"当前用户已存在")
continue
else:
user_data[username] = {
"username": username,
"password": password,
"age": age,
"gender": gender,
"role": role
}
data_list = []
for line in [item.values() for item in user_data.values()]:
data_list.append('|'.join([str(i) for i in line]) + '\n')
with open("user_data.text", "w", encoding="utf-8") as fp:
fp.writelines(data_list)
print(f"{username}注册成功")
continue
elif func_id == 2:
print(f"欢迎来到登陆功能")