对象持久化
扁平文件
格式话文本文件代码:
def write_scores():
with open('data_list.txt', 'w', encoding='utf8') as f:
f.write(str(scores))
def read_scores():
with open('data_list.txt', 'r', encoding='utf8') as f:
lst = eval(f.read())
lst[0] = 99
print(lst)
if __name__ == '__main__':
write_scores()
read_scores()
上述代码中,将一个数据类型写入到文件中,只能通过字符串的写入,如果读取时,利用list将字符串还原,它会将真个字符串每个字符一次还原,包括[,因此可以使用py的内置函数eval,将str堪称py表达式运行。
但这种方式对于传不同类型的参数比较麻烦,在为止的前提下无法区分数据。
pickle模块
person = {'name': 'Tom', 'age': 20}
s = pickle.dumps(person)
print(s)
p = pickle.loads(s)
print(p)
pickle.dump(person, open('pickle_db', 'wb'))
p = pickle.load(open('pickle_db', 'rb'))
print(p)
dumps序列化生成二进制字节类型,写入文件时,要使用wb,loads也是反序列化字节类型数据,dump和load时可以直接写入文件和在文件中加载。
pickle模块的方法,针对每一个数据类型的对象,只能写入一个文件,不可以在一个文件里写入多个类型的对象,如果向一次写入多个,可以借助字典表。
shelve模块
import shelve
scores = [99, 88, 77]
student = {'name': 'Mike', 'age': 20}
db = shelve.open('shelve_student')
db['s'] = student
db['scores'] = scores
print(len(db))
temp_student = db['s']
print(temp_student)
type(temp_student)
del db['scores']
print(len(db))
db.close()
shelve模块可以利用字典键值的原理来存储各种数据类型,有效的解决了其他序列化方式的不足,在利用shelve打开文件,获得一个对象后,需要在不使用时将其关闭。
同样的,shelve也可以将一个类的对象序列化:
import shelve
class Student:
def __init__(self, name='', age=0):
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()
def raad_shelve():
db = shelve.open('shelve_student_db')
st = db['s']
print(st)
print(st.name)
db.close()
if __name__ == '__main__':
write_shelve()
raad_shelve()
字符串
概述
类型有:字符串str、字节bytes(不可变)、字节数组bytearray(可变)
字符编码架构:
- 字符集:赋值一个编码到内存中,以便在内存中表示(Unicode就是典型的字符集标准)
- 编码Encoding:转换字符到原始编码(ASCII、UTF8都是典型的编码规则)
- 解码 Decoding:依据编码名称转换原始字节到字符的过程
字符串存储时,编码只作用于文件存储或中间媒介转换时,内存中总是存储解码以后的文本。
字符编码
常用的ASCII编码,存储在一个byte 0-127,只有128个字符,latin-1编码,存储在存储在一个Byte 128-255,而UTF-8的编码方式,不仅兼容了ASCII,同时还是一个可变长的,0-127代码点使用单字节、128-207代码点使用双字节、大于2047的使用3-4byte。注:这里说的代码点是以常用的unicode为基础的。
>>> ord('A')
65
>>> chr(68)
'D'
>>> chr(223)
'ß'
>>> chr(202)
'Ê'
>>> ord('优')
20248
>>> s1 = 'ABCD'
>>> s1.encode('ASCII')
b'ABCD'
>>> s2 = '优品课堂'
>>> type(s2)
<class 'str'>
>>> s2.encode('ASCII')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
>>> s2.encode('UTF-8')
b'\xe4\xbc\x98\xe5\x93\x81\xe8\xaf\xbe\xe5\xa0\x82'
>>> b1=b'\xe4\xbc\x98\xe5\x93\x81\xe8\xaf\xbe\xe5\xa0\x82'
>>> b1.decode('UTF-8')
'优品课堂'
>>> b1.decode('utf-16')
'볤\ue598膓꿨\ue5be芠'
>>> s1.encode('UTF-8')
b'ABCD'
>>> s1.encode()
b'ABCD'
可以使用内置函数ord来获取一个字符的代码点,也可以格局一个代码点使用chr函数获取字符。
str.encode(‘编码’),是将特定的字符串,按照制定的编码方式编码,bytes.decoding('编码‘)是将字节类型,解码成字符串。s2使用ASCII编码时出错,时因为ASCII不支持中文的字符,因此无法编码。如果参数不写,则使用默认的编码方式。py的默认编码方式是utf8。
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
文件的写入也可以制定编码方式,如果不写,则默认的是gbk方式:
>>> open('date.txt','w',encoding='utf-8').write('优品课堂')
4
>>> open('date.txt','r',encoding='utf-8').read()
'优品课堂'
>>> open('date2.txt','w').write('优品课堂')
4
>>>
>>> open('date2.txt','r',encoding='gbk').read()
'优品课堂'
类型转换
>>> s = 'abc'
>>> s1='优品课堂'
>>> s.encode()
b'abc'
>>> s1.encode()
b'\xe4\xbc\x98\xe5\x93\x81\xe8\xaf\xbe\xe5\xa0\x82'
>>> open('date.txt','r',encoding='utf-8').read()
'优品课堂'
>>> open('date.txt','rb').read()
b'\xe4\xbc\x98\xe5\x93\x81\xe8\xaf\xbe\xe5\xa0\x82'
>>> bytes('abc','ascii')
b'abc'
>>> bytes('优品课堂','utf-8')
b'\xe4\xbc\x98\xe5\x93\x81\xe8\xaf\xbe\xe5\xa0\x82'
>>> bytes([87,65,89,87])
b'WAYW'
>>> b=b'abc'
>>> type(b)
<class 'bytes'>
bytes类型可以通过一下三种方式转换:
- 手动声明 b’ ’
- 字符编码 str.encoding()
- 构造函数 bytes(’字符串‘,’编码方式‘),只能转换0-256范围内的数。
上述代码的转换中,因为ASCII的代码点与编码后的二进制数一致,因此显示时,是显示的一样,只是在最前面加一个b。
>>> s1 = 'abd'
>>> s2 = '优品课堂'
>>> ba = bytearray(s1,'utf-8')
>>> type(ba)
<class 'bytearray'>
>>> ba
bytearray(b'abd')
>>> ba[0]
97
>>> ba[0]=98
>>> ba
bytearray(b'bbd')
>>> ba.append(212)
>>> ba
bytearray(b'bbd\xd4')
>>> ba+b'c!'
bytearray(b'bbd\xd4c!')
>>> ba.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd4 in position 3: unexpected end of data
>>>
bytearray的方法跟list的很多方法一致。
代码最后报错的原因是utf8对于大于127的数字是按照两位编码的,因此\xd4是大于127的数,但只有一个字节,因此报错。
BOM
f = open('date.txt', 'r', encoding='utf-8')
a = f.read()
print(a)
f.close()
f1 = open('date3.txt', 'w', encoding='utf-8-sig')
f1.write('优品课堂')
f1.close()
#只有在控制台才行
f2 = open('date3.txt', 'r', encoding='utf-8')
b = f2.read()
print(open('date3.txt','r',encoding='utf-8').read())
f2.close()
# 最后两行代码的输出
'\ufeff优品课堂'
当在编码的后面加上-gis,表示写入时,在字符串前加上字符顺序标记。当读取时,加上-gis,可以消除字符顺序标记。