对象持久化
对象持久化:将当前正在计算的数据结果或者状态永久存储存。
扁平文件
利用文本文件存储信息,首先将需要储存的变量转化为文本信息,再写入到文件中,使用时再将文本信息反序列化。
例:将列表存储到文本文件中再读取出来。
scores = [88, 99, 77, 55] #需要存储的值
def write_scores(): #写入文本文件
with open('data_list.txt','w',encoding='utf8') as f:
f.write(str(scores))
print('文件写入完成...')
if __name__ == '__main__':
write_scores()
写入结果
data_list.txt文件
读取文件内容
def read_scores():
with open('data_list.txt', 'r', encoding='utf8') as f:
lst = f.read()
print(lst)
if __name__ == '__main__':
read_scores()
#运行结果
[88, 99, 77, 55]
读取出的结果看起来像列表,其实只字符串,不能进行列表操作。
def read_scores():
with open('data_list.txt', 'r', encoding='utf8') as f:
lst = f.read()
lst[0] = 99
print(lst)
if __name__ == '__main__':
read_scores()
#运行结果
TypeError: 'str' object does not support item assignment
使用list()函数进行转换,会将字符串中每一个字符都转化为列表元素,包括符号。
def read_scores():
with open('data_list.txt', 'r', encoding='utf8') as f:
lst = f.read()
print(list(lst))
if __name__ == '__main__':
read_scores()
#运行结果
['[', '8', '8', ',', ' ', '9', '9', ',', ' ', '7', '7', ',', ' ', '5', '5', ']']
eval()函数可将文本文件中的内容直接转化为python语句。
def read_scores():
with open('data_list.txt', 'r', encoding='utf8') as f:
lst = eval(f.read())
print(lst)
lst[0] = 99
print(lst)
if __name__ == '__main__':
read_scores()
pickle
pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议。“Pickling”是将Python对象层次结构转换为字节流的过程, “unpickling”是反向操作,从而将字节流(来自二进制文件或类似字节的对象)转换回对象层次结构。
序列化到字符串
1、pickle.dumps(obj) 将对象序列化为字符串。
2、pickle.loads(obj) 从字符串反序列化对象。
>>> import pickle
>>> person = {'name':'Tom','age':20}
>>> s = pickle.dumps(person) #将一个字典表序列化为字节字符串
>>> s
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00Tomq\x02X\x03\x00\x00\x00ageq\x03K\x14u.'
>>> p = pickle.loads(s) #将字节字符串反序列化为原对象
>>> p
{'name': 'Tom', 'age': 20}
>>> type(p) #反序列化后的对象和之前的类型一样
dict
序列化到文件
1、pickle.dump(obj,file) 将对象序列化为文件。
2、pickle.load(file) 载入文件内容。
>>> import pickle
>>> person = {'name':'Tom','age':20}
>>> pickle.dump(person, open('pickle_db', 'wb'))
运行生成一个二进制文件pickle_db。
读取文件内容
>>> p = pickle.load(open('pickle_db', 'rb'))
>>> p
{'name': 'Tom', 'age': 20}
>>> type(p)
Out[12]: dict
shelve
当需要将多个变量储存到一个文件中时,可以使用shelve模块。
1、shelve.open(‘dbfile’) 创建数据库文件
2、db[‘key’] = obj 存储对象
3、len(db) 查看存储对象数量
4、del db[‘key’] 删除存储对象
5、db.close() 关闭当前文件
#创建一个名为shelve_student的二进制文件
import shelve
db = shelve.open('shelve_student')
将一个字典表及一个列表存储到刚才的文件中
>>> student = {'name': 'Tom', 'age': 20}
>>> scores = [99, 88, 77]
>>> db['s'] = student
>>> db['scores'] = scores
查看文件存储对象的个数
>>> len(db)
2
加载文件中存储的变量
#加载存储的字典表
>>> temp_student = db['s']
>>> temp_student
{'name': 'Tom', 'age': 20}
>>> type(temp_student)
dict
#加载存储的列表
>>> temp_scores = db['scores']
>>> temp_scores
[99, 88, 77]
>>> type(temp_scores )
list
可以删除文件中存储的对象
>>> del db['scores'] #删除对象scores
>>> len(db) #长度变为1
1
>>> db['s'] #对象s依然存在
{'name': 'Tom', 'age': 20}
>>> db['scores'] #加载对象scores会报错
Traceback (most recent call last):
File "E:\software\anaconda3\azwj\lib\shelve.py", line 111, in __getitem__
value = self.cache[key]
KeyError: 'scores'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "E:\software\anaconda3\azwj\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-32-76dcfbb20b51>", line 1, in <module>
db['scores']
File "E:\software\anaconda3\azwj\lib\shelve.py", line 113, in __getitem__
f = BytesIO(self.dict[key.encode(self.keyencoding)])
File "E:\software\anaconda3\azwj\lib\dbm\dumb.py", line 153, in __getitem__
pos, siz = self._index[key] # may raise KeyError
KeyError: b'scores'
将一个类实例存储到数据库文件
import shelve
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return self.name
def write_shelve():
s = Student('Tom', 20)
db = shelve.open('shelve_student_db')
db['s'] = s
db.close()
if __name__ == '__main__':
write_shelve()
运行后出现shelve_student_db文件
加载存储的实例
def read_shelve():
db = shelve.open('shelve_student_db')
st = db['s']
print(st)
print(st.name)
print(st.age)
db.close()
if __name__ == '__main__':
read_shelve()
#运行结果
Tom
Tom
20
字符串本质
概述
1、类型
在Python3中字符串相关的类型有三种:
(1) str: 字符串
(2) bytes: 字节(不可变)
(3) bytearray: 字节数组(可变)
将字符变为字节的过程称为编码,将字节转为字符的过程称为解码。
2、字符编码架构
(1)字符集:赋值一个编码到某个字符,以便在内存中表示;
(2)编码Encoding:转换字符到原始字节形式;
(3)解码Decoding:依据编码名称转换原始字节为字符的过程。
3、字符串存储
(1)编码只作用于文件存储或中间媒介转换时;
(2)内存中总是存储解码以后的文本。
字符编码
一、ASCII
美国信息交换标准代码,基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。存储在一个字节(Byte), 0-127代码点。
>>> ord('A') #获取字符代码点
65
>>> chr(104) #获取代码点对应的字符
'h'
二、latin-1
超出ASCII包含的字母及符号,存储在一个Byte,128-255代码点。
>>> chr(202)
'Ê'
>>> ord('ß')
223
三、UTF-8
可变字节,相对通用,兼容ASCII。
(1)0-127 使用单字节
(2)128-2047 双字节存储
(3)>2047 3-4Byte
(4)每Byte使用 128-255
>>> ord('学')
23398
>>> chr(20249)
'伙'
四、UTF-16
2Byte存储字符(另加2Byte作为标识),兼容性高但内存占用大。
五、UTF-32
4Byte存储字符,兼容性高但内存占用大。
字节与文本的编码、解码
1、str.encode(‘编码’) 将特定字符编码
>>> s1 = 'ABCD'
>>> s1.encode('ASCII')
b'ABCD' #前面带有吧,表示为字节码,而非字符串
>>> type(s1)
str
>>> type(s1.encode('ASCII'))
bytes
>>> s2 = '学习'
>>> s2.encode('UTF-8')
b'\xe5\xad\xa6\xe4\xb9\xa0'
编码器选择不当可能会报错,例如用ASCII对汉字编码。
>>> s2.encode('ASCII')
Traceback (most recent call last):
File "E:\software\anaconda3\azwj\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-44-2aa70292e6ab>", line 1, in <module>
s2.encode('ASCII')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
使用不同的编码器,若不报错,则产生不同的字节码。
>>> s2.encode('UTF-16')
b'\xff\xfef[`N'
>>> s2.encode('UTF-32')
b'\xff\xfe\x00\x00f[\x00\x00`N\x00\x00'
2、bytes.decode(‘编码’) 将字符编码解码为字符文本
>>> b1 = b'\xe5\xad\xa6\xe4\xb9\xa0'
>>> b1.decode('utf-8')
'学习'
若编码与解码时使用的编码器不同,则会出现乱码或报错
>>> b1.decode('utf-16')
'귥\ue4a6ꂹ'
编码器可以不指定,默认使用UTF-8
>>> b1.decode()
'学习'
类型转换
1、字节bytes
(1)手动声明 :b’
>>> b = b'abc'
>>> type(b)
bytes
(2)字符串编码 str.encode()
>>> s = 'abc'
>>> s1 = '学习'
>>> s.encode()
b'abc'
>>> s1.encode()
b'\xe5\xad\xa6\xe4\xb9\xa0'
(3)构造函数 bytes()
>>> s = 'abc'
>>> s1 = '学习'
>>> bytes(s,'ascii')
b'abc'
>>> bytes(s1,'utf8')
b'\xe5\xad\xa6\xe4\xb9\xa0'
2、字节数组bytearray
(1)编码:bytearray(‘字符’,‘编码’)
>>> s1 = 'abc'
>>> ba = bytearray(s1,'utf8')
>>> ba
bytearray(b'abc')
>>> type(ba)
bytearray
字节数组是可变的
#更改元素
>>> ba[0]
97
>>> ba[0] = 98
>>> ba
bytearray(b'bbc')
#追加元素
>>> ba.append(212)
>>> ba
bytearray(b'bbc\xd4')
#当追加的字节超过编码器范围会报错
>>> ba.append(2122)
Traceback (most recent call last):
File "E:\software\anaconda3\azwj\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-74-b57d1b0622e0>", line 1, in <module>
ba.append(2122)
ValueError: byte must be in range(0, 256)
(2)解码为字符串 .decode()
>>> ba = bytearray('abc','utf8')
>>> ba.append(93)
>>> ba.decode('utf8')
'abc]'
>>> type(ba.decode('utf8'))
str
BOM处理
读取文件内容时可能会出现字节顺序标记,在指定解码器时加上“-sig”可以避免,如:open(‘data.txt’,‘r’,encoding=‘utf-8-sig’).read()。