帮忙做网站,川汇网站建设,网络广告电话,珠海个人建站模板1. 将对象存储到本地
假如有一个student类#xff0c;我们定义了好几个对象#xff0c;想要把这些对象存储下来#xff0c;该怎么办呢
from typing import List
class Student:name: strage: intphones: List[str]
s1 Student(xiaoming,10,[huawei我们定义了好几个对象想要把这些对象存储下来该怎么办呢
from typing import List
class Student:name: strage: intphones: List[str]
s1 Student(xiaoming,10,[huawei,xiaomi])一个极其简单的想法是把这些对象的值拼接到一起编程字符串存储下来字段与字段之间使用逗号隔开list的字段则使用#号隔开想要使用什么字符自己定只要约定好即可
# xiaoming,10,huawei#xiaomires ,.join(s1.name,s1.age,#.join(s1.phones))
with open(s1.txt,w) as f:f.write(res)读取这个字符串后按照我们的约定再反解析出来每个字段
with open(s1.txt,r) as f:res f.read()name,age,phones res.split(,)
phones phones.split(#)s1 Student(name, age, phones)
这样我们就又可以得到这个对象了。
存储数据的过程就是序列化解析数据的过程就是反序列化
2. 字符串编码
我们把对象转换成字符串存到了本地文件中并且可以打开这个文件看到我们的字符串。一切好像都很自然。其实中间存在了一个小gap我们知道计算机只认识二进制为啥存储的时候没有变成bytes反而可以是字符串呢我们把open函数补全一点儿
with open(s1.txt,w,encodingutf-8) as f:f.write(res)可以看到多了一个encoding的参数就是使用utf-8的方式把这段字符串编码成二进制数据。
计算机只认识二进制要想传输一个对象必须将其转换成二进制格式。英文有26个字符还有一些常用的符号一个想当然的方法就是让每个字符对应一个数字这就是ASCII码表例如
二进制十进制十六进制图形0010 00003220空格(␠)0010 00013321!0100 00016541A0110 00019761a
英文是解决了中文呢日文呢俄文呢为了把所有的文本统一搞出了一个unicode码本每个文本都对应了一个二进制。unicode使用4个字节表示一个字符这对于英文来说就非常的浪费内存英国人跟英国人交流基本都是英文他们浏览网站看到的也基本是英文同样对于中文来说也一样。所以就提出了utf-8的【编码方式】utf-8是一种变长编码方式对于英文来说只需要一个字节就可以了中文只需要3个字节。 这里需要注意的是utf-8是一种unicode的编码方式打个比方每个人的手机号都是11位的但是如果你办了亲情网只需要3位就可以标识自己的老公老婆父母了。11位的手机号相当于unicode可以表示全国所有的人而亲情网则可以认为是utf-8编码得到的那3位就是utf-8编码后的号码。
通过unicode码本可以把字符映射成unicode二进制通过utf-8编码可以把unicode二进制转换成更短的二进制 我就想为啥不直接使用utf-8作为码本呢 所以不要觉得是我们把字符串写到本地了其实这个字符串通过utf-8编码已经变成二进制存储到本地了。 也不要觉得我们直接打开的是字符串其实通过notepad打开的是二进制只不过notepad给我们使用utf-8解码了。将这个二进制重新映射成了unicode通过unicode找到对应的字符给我们显示了出来。
编码转换
使用统一的unicode编码后每个人看到的就不会是乱码了俄文日文都可以在我们的电脑上正确的展示出来了。utf-8需要3个字节表示一个中文但其实只需要2个字节就可以了utf-8对中文而言也是有点浪费了所以提出了gbk编码只需要2个字节来表示中文。引文只是对中文进行编码如果想要显示俄文那么就会是乱码。 我们请求网页的时候都会告知这个网页的编码方式一般都是utf-8的这样兼容性很好任意字符都可以显示也有gbk编码的。
如果一个文本使用utf-8编码使用gbk格式打开就会乱码同样如果使用gbk编码使用utf-8就会乱码。我们可以先使用对应的编码方式打开这样得到其实就是unicode码然后再使用想要的编码方式去保存。 这么说来的话unicode算是一种事实标准了 4. json序列化
回过头来我们把对象转换成字符串存储到了本地也可以根据存储的规则反推出原来的对象这个过程称之为序列化和反序列化用逗号分隔的格式一般称为csv。更多会使用json格式来进行序列化。
import json
from typing import Listclass Phone:name: strtime: strclass Student:name: strage: intphones: List[Phone]
p1 Phone(xiaomi, 2024)
p2 Phone(huawei, 2008)
s1 Student(xiaoming,10,[p1, p2])res {}res[name] s1.name
res[age] s1.age
res[phones] [{name:xiaomi,time:2024},{name:huawei,time:2008}]res_str json.dumps(res) # 把对象转换成字符串with open(s1.txt,w) as f:f.write(res_str)with open(s1.txt,r) as f:obj json.loads(f.read())s2 Student()
s2.name obj[name]
s2.age obj[age]
phones2 []
for phone in obj[phones]:phones2.appen(Phone(phone.name,phone.time))
s2.phones phones2
首先把对象转换成json支持的类型json支持listtupledictintstr等基础类型通过json的dumps函数我们可以把对象转换成字符串并写到本地
proto序列化
protobuf本质就是一个【数据结构】例如下面定义一个student的pb文件
syntax proto2;
package tutorial;message Phone{optional string name 1;optional string time 2;
}message Student {optional string name 1;optional int32 age 2;repeated Phone phones 3;
}
message可以认为就是classrepeated其实就是list 同样
将原始对象转成pb格式的对象使用seriral序列化函数转换成字符串并写入到本地
2. proto生成相应的类
proto文件最终通过proto会生产相应的类文件如果是c的话就是student.pb.cc和student.pb.h。
protoc --proto_path. --cpp_out. ./student.proto如果是python则是student_pb2.py。
protoc --proto_path. --python_out. ./student.protoproto_path是搜索proto的路径而cpp_out是生产.cc和.h的路径最后则是我们的proto路径。在这里的相对路径是相对于protoc执行的路径而言的哪里执行命令哪里就是工作路径。 例如proto文件存储在/a/b/test/addressbook.proto执行protoc的路径是/c/d此时proto_path和cpp_out使用的相对路径都是相对于/c/d而言的。