Python Protocol Buffers中Map字段是否有拷贝构造函数?如何实现拷贝?
Python Protobuf Map字段拷贝技巧(无需手动遍历所有键值对)
刚好碰到过这个棘手的问题!官方的Python Protobuf生成代码文档里确实没覆盖map拷贝的场景——既没法直接赋值(尤其是值为嵌套消息的情况),map本身又不是消息类型,没有CopyFrom方法,还不想为了一个map拷贝整个消息。下面分两种情况给你高效的解决方案:
1. 键值为基本类型的Map(int/string/bool等)
如果你的map里都是基础数据类型,直接用Protobuf map自带的update方法就行,这会批量把源map的所有键值对拷贝到目标map里,完全不用手动遍历:
# 示例:src_msg里有map字段source_map,dest_msg是目标消息 dest_msg.target_map.update(src_msg.source_map)
这个方法做的是值拷贝,修改目标map不会影响源map,完美满足需求。
2. 值为嵌套Protobuf消息的Map
如果map的值是嵌套的消息对象,直接用update只会拷贝对象引用(修改目标里的消息会同步改源消息),这时候需要结合消息的CopyFrom方法做深拷贝。虽然底层还是会遍历,但不用手动写循环逻辑,几行代码就能搞定:
# 先批量创建空的嵌套消息对象,再拷贝内容 dest_msg.target_map.update({k: v.__class__() for k, v in src_msg.source_map.items()}) for key, src_item in src_msg.source_map.items(): dest_msg.target_map[key].CopyFrom(src_item)
要是想更紧凑,也可以写成一行(可读性稍弱,但代码量少):
dest_msg.target_map.update( {k: (lambda new_msg: (new_msg.CopyFrom(src_item), new_msg)[1])(v.__class__()) for k, src_item, v in zip(src_msg.source_map.keys(), src_msg.source_map.values(), src_msg.source_map.values())} )
本质上嵌套消息必须做深拷贝,没法完全避开遍历操作,但至少不用手动逐个处理每个键值对。
为什么不能直接赋值?
顺带解释下坑点:Protobuf生成的map字段是只读属性,直接dest_msg.target_map = src_msg.source_map会报错;就算是普通字典,直接赋值也是引用传递,修改一个会影响另一个,根本不是拷贝。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

