You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中自定义格式打印Protobuf消息?

解决Protobuf中MAC/IP地址字段可读性打印问题

当Protobuf消息中的bytes类型字段存储MAC、IP这类地址时,默认打印会输出转义的字节序列(比如"\000\016\037\204\222\333"),可读性极差。如果不想为每个消息单独编写打印函数,可以通过以下通用方案解决:

方案1:自定义通用格式化函数(简单直接)

编写一个遍历消息字段的通用函数,根据字段名或类型自动格式化MAC/IP地址:

import health_pb2
from google.protobuf.descriptor import FieldDescriptor

def format_protobuf_msg(msg):
    output_lines = []
    # 遍历消息的所有字段和值
    for field, value in msg.ListFields():
        if field.type == FieldDescriptor.TYPE_BYTES:
            # 根据字段名识别MAC地址
            if "mac_addr" in field.name:
                mac_str = ":".join(f"{byte:02x}" for byte in value)
                output_lines.append(f'{field.name}: "{mac_str}"')
            # 根据字段名识别IPv4地址
            elif "ip_addr" in field.name:
                ip_str = ".".join(str(byte) for byte in value)
                output_lines.append(f'{field.name}: "{ip_str}"')
            # 其他bytes字段保留默认格式
            else:
                output_lines.append(f'{field.name}: {repr(value)}')
        else:
            # 非bytes字段按默认格式输出
            output_lines.append(f'{field.name}: {value}')
    return "\n".join(output_lines)

# 使用示例
if __name__ == "__main__":
    health = health_pb2.Health()
    health.device_uptime = 17
    health.mac_addr = bytes.fromhex("000e1f8492db")
    print(format_protobuf_msg(health))

这个方案依赖字段名的统一命名规则(比如包含mac_addr、ip_addr),适合字段命名规范的项目。

方案2:自定义TextFormat访问器(支持嵌套消息,更原生)

基于Protobuf原生的text_format模块,自定义访问器重写bytes字段的处理逻辑,支持嵌套消息等复杂结构:

from google.protobuf import text_format
from google.protobuf.descriptor import FieldDescriptor
import health_pb2

class AddressFormatVisitor(text_format.PrintVisitor):
    def VisitBytes(self, value, field):
        # 识别MAC地址字段并格式化
        if "mac_addr" in field.name:
            formatted_mac = ":".join(f"{byte:02x}" for byte in value)
            return f'"{formatted_mac}"'
        # 识别IPv4地址字段并格式化
        elif "ip_addr" in field.name:
            formatted_ip = ".".join(str(byte) for byte in value)
            return f'"{formatted_ip}"'
        # 其他bytes字段使用默认处理逻辑
        return super().VisitBytes(value, field)

def print_formatted_msg(msg):
    visitor = AddressFormatVisitor()
    text_format.Print(msg, visitor=visitor)
    print(visitor.ToString())

# 使用示例
if __name__ == "__main__":
    health = health_pb2.Health()
    health.device_uptime = 17
    health.mac_addr = bytes.fromhex("000e1f8492db")
    print_formatted_msg(health)

方案3:结合Protobuf自定义字段选项(最灵活可靠)

如果字段命名不统一,可以在proto文件中定义自定义字段选项,标记哪些字段是MAC/IP地址,实现更精准的识别:

1. 修改proto文件,添加自定义选项

import "google/protobuf/descriptor.proto";

// 定义自定义字段选项
extend google.protobuf.FieldOptions {
  bool is_mac_addr = 50001;  // 标记该字段为MAC地址
  bool is_ipv4_addr = 50002; // 标记该字段为IPv4地址
}

message Health {
    bytes mac_addr = 1 [(is_mac_addr) = true];
    uint32 device_uptime = 2;
    // 其他字段...
}

2. 在Python中使用自定义选项处理字段

from google.protobuf import text_format
import health_pb2

class AddressFormatVisitor(text_format.PrintVisitor):
    def VisitBytes(self, value, field):
        # 通过自定义选项判断是否为MAC地址
        if field.GetOptions().Extensions[health_pb2.is_mac_addr]:
            formatted_mac = ":".join(f"{byte:02x}" for byte in value)
            return f'"{formatted_mac}"'
        # 通过自定义选项判断是否为IPv4地址
        elif field.GetOptions().Extensions[health_pb2.is_ipv4_addr]:
            formatted_ip = ".".join(str(byte) for byte in value)
            return f'"{formatted_ip}"'
        return super().VisitBytes(value, field)

# 使用方式同方案2

这种方案不依赖字段名,通过显式标记实现精准处理,适合大型或字段命名不统一的项目。

内容的提问来源于stack exchange,提问作者Abdurrahman Uslu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:33:52