各位大佬好,想请问一下 Python 如何基于反射的方法去实现 json 格式和 pb 文件的相互转换,
pb 文件值的是编译过的 pb2.py 文件?还是原生的 protobuf 文件?
那无解,反射解决不了格式转换,protobuf 原生文件里可能依赖有大量的第三方依赖,例如 google 的 int64 数据格式,这些数据格式是 Python 不支持的,还是需要编译 protobuf 之后拿到 pb2.py 文件才能调用
那如何基于 编译后的 pb2.py 文件,进行 json 和 pb 序列化数据的准换呢
目前了解到的是都是需要 import ***pb2.py 然后再根据 protobuf 文件结构去序列化和反序列化。 但是这种方式因为在第一行要导入模块所以感觉不太通用。是想做一个通用的方法去解析多个 protobuf 文件然后在官网上了解到 reflection 模块中 ParseMessage 方法
.protobuf.reflection.ParseMessage(descriptor, byte_str)
但这个方法第一个参数对象的初始化里面很多参数都不太清楚
class google.protobuf.descriptor.Descriptor(name, full_name, filename, containing_type, fields, nested_types, enum_types, extensions, options=None, serialized_options=None, is_extendable=True, extension_ranges=None, oneofs=None, file=None, serialized_start=None, serialized_end=None, syntax=None, create_key=None)
可以看下官方文档,google.protobuf.json_format 可以解决你遇到的问题,ParseDict(buffer, msg), MessageToDict(msg)
非常感谢解答,但是还是有几点疑惑哈第一个是 self.descriptor.FindFileByName(file_name)¶ 这个方法传参应该是一个文件名字吧,返回的是一个 FileDescriptor 对象。但是 GetMessages() 传参对象是一个 file_protos – Iterable of FileDescriptorProto 是不能直接传递的吧
构造方法里面调用 addModule,会把你的 pb 对象都加载到内存,有两个方法写错了,外网没有 pb,不能 debug,python 的 ide 不是强类型检查,自动补全没仔细看,所以写错了,不好意思哈,代码看下面
我理解你是否想把 python 的 dict 直接转成 pb2.py 文件中的具体的信息类?然后自动填充对应的字段?希望对你有帮助
import simplejson
from google.protobuf.descriptor import FieldDescriptor as FD
class ConvertException(Exception):
pass
def dict2pb(cls, adict, strict=False):
obj = cls()
for field in obj.DESCRIPTOR.fields:
if not field.label == field.LABEL_REQUIRED:
continue
if not field.has_default_value:
continue
if not field.name in adict:
raise ConvertException('Field "%s" missing from descriptor dictionary.'
% field.name)
field_names = set([field.name for field in obj.DESCRIPTOR.fields])
if strict:
for key in adict.keys():
if key not in field_names:
raise ConvertException(
'Key "%s" can not be mapped to field in %s class.'
% (key, type(obj)))
for field in obj.DESCRIPTOR.fields:
if not field.name in adict:
continue
msg_type = field.message_type
if field.label == FD.LABEL_REPEATED:
if field.type == FD.TYPE_MESSAGE:
for sub_dict in adict[field.name]:
item = getattr(obj, field.name).add()
item.CopyFrom(dict2pb(msg_type._concrete_class, sub_dict))
else:
map(getattr(obj, field.name).append, adict[field.name])
else:
if field.type == FD.TYPE_MESSAGE:
value = dict2pb(msg_type._concrete_class, adict[field.name])
getattr(obj, field.name).CopyFrom(value)
else:
setattr(obj, field.name, adict[field.name])
return obj
instance 回来的是 bool 值哦,create 的时候需要引入 proto 的类型,createPB("log_pb2.logTag")