事情的起源是出于加深protobuf理解的目的想深入的研究下pb的编码规则。为此有如下实例:
message Test
{
required int32 num1 = 1;
required fixed32 num2 = 2;
}
对这个结构实例化一个对应num1和num2分别赋值10 和 1073741824 。链接 中输出序列化后的16进制表示为和2进制表示如下:
十六进制表示为:
080a 1500 0000 40
二进制表示为:
00001000000010100001010100000000000000000000000001000000
出于快速的目的我采用python来实现,代码如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import test_pb2
test1=test_pb2.Test()
test1.num1=10
test1.num2=1073741824
buf=test1.SerializeToString()
print("buf:",buf)
得到的输出结果如下:

对比如下。两者看起来应该是相同的,但是有两个位置却又不同。很是奇怪。
b'\x08\n\x15\x00\x00\x00@'
080a 15 00 00 0040
>>> b"\x0a"
b'\n'
>>> b"\x40"
b'@'
这里先说结论:两者确实是一个东西,只不过在python的输出中把能转义输出的字符都转义输出了而已。
如上图 ‘\n’其实是‘\x0a’,‘@’其实是‘\x40’。这些都是可以在ASCII码表中查到的,例如‘\x0a’就是十进制的10,对应ASCII码表就是换行'\n'。
(1)对于ASCII字符python输出的是字符本身; 对于非ASCII的字符输出的是它的字符编码值(十六进制形式)而不是字符本身。
(2)对于非ASCII字符是十六进制表示编码值。
1、对于ASCII字符python输出的是字符本身; 对于非ASCII的字符输出的是它的字符编码值(十六进制形式)而不是字符本身。如下:
>>> 'abcd'.encode()
b'abcd'
>>> '@'.encode()
b'@'
>>> '我'.encode()
b'\xe6\x88\x91'
2、对于非ASCII字符是十六进制表示编码值,例如对于上面的'我'。
(1)其中的'\x'表示后面的数是十六进制
(2)e、6等分别是一个十六进制编码值
>>> s="我我python"
>>>
>>> s.encode()
b'\xe4\xbd\xa0\xe5\xa5\xbdpython'
python2与python3在str/bytes方面的区别
1、python2
python2有basestring、str、bytes、unicode四种类型。
其中str=bytes,basestring=(str,unicode)。
2、python3
python3有str和bytes两种类型,是严格区分开的。不能混用。
这就是为什么有些python2中能运行的脚本,在python3中会有类似“TypeError: 'XXXX' has type str, but expected one of: bytes” 报错的原因。
这个时候使用以下后面说到的 bytes(XXXX, encoding = "utf8") 对XXXX进行以下转换就好了。
关于encode的作用
encode()的作用是将str转换为bytes类型;
decode()的作用是将bytes转换为str类型;
>>> a='abcd'
>>> type(a)
<class 'str'>
>>>
>>> type(a.encode())
<class 'bytes'>
>>>
>>> type(a.encode().decode())
<class 'str'>
python3的str和byte相互转换
# bytes object
b = b"example"
# str object
s = "example"
# str to bytes
bytes(s, encoding = "utf8")
# bytes to str
str(b, encoding = "utf-8")
# an alternative method
# str to bytes
str.encode(s)
# bytes to str
bytes.decode(b)
|