Цикл по атрибутам буферов протокола в Python

Я хотел бы помочь с рекурсивным циклом по всем атрибутам / подчиненным объектам, содержащимся в сообщении буферов протокола, предполагая, что мы не знаем их имен или их количества.

В качестве примера возьмем следующий файл.proto из учебника на веб-сайте Google:

  message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

и использовать это...

person = tutorial.Person()
person.id = 1234
person.name = "John Doe"
person.email = "jdoe@example.com"
phone = person.phone.add()
phone.number = "555-4321"
phone.type = tutorial.Person.HOME

Дано PersonКак мне получить доступ к имени атрибута и его значению для каждого элемента: person.id, person.name, person.email, person.phone.number, person.phone.type?

Я пробовал следующее, однако, похоже, не повторяется в person.phone.number или же person.phone.type,

object_of_interest = Person

while( hasattr(object_of_interest, "_fields") ):
  for obj in object_of_interest._fields:
    # Do_something_with_object(obj) # eg print obj.name
    object_of_interest = obj

Я пытался использовать obj.DESCRIPTOR.fields_by_name.keys для доступа к подчиненным элементам, но это строковые представления вложенных объектов, а не сами объекты.

obj.name дает мне атрибут имени, но я не уверен, как на самом деле получить значение этого атрибута, например, obj.name может дать мне "имя", но как мне извлечь из него "Джон Доу"?

2 ответа

Решение

Я не очень хорошо знаком с protobufs, поэтому вполне может быть более простой способ или API для такого рода вещей. Тем не менее, ниже показан пример того, как вы можете перебирать / анализировать поля и объекты и распечатывать их. Надеюсь, по крайней мере, чтобы вы пошли в правильном направлении, по крайней мере...

import addressbook_pb2 as addressbook

person = addressbook.Person(id=1234, name="John Doe", email="foo@example.com")
person.phone.add(number="1234567890")


def dump_object(obj):
    for descriptor in obj.DESCRIPTOR.fields:
        value = getattr(obj, descriptor.name)
        if descriptor.type == descriptor.TYPE_MESSAGE:
            if descriptor.label == descriptor.LABEL_REPEATED:
                map(dump_object, value)
            else:
                dump_object(value)
        elif descriptor.type == descriptor.TYPE_ENUM:
            enum_name = descriptor.enum_type.values[value].name
            print "%s: %s" % (descriptor.full_name, enum_name)
        else:
            print "%s: %s" % (descriptor.full_name, value)

dump_object(person)

какие выводы

tutorial.Person.name: John Doe
tutorial.Person.id: 1234
tutorial.Person.email: foo@example.com
tutorial.Person.PhoneNumber.number: 1234567890
tutorial.Person.PhoneNumber.type: HOME

Если вы хотите получить все поля, определенные в базовом прото-классе (а не только те, которые установлены в данном экземпляре), вы можете сделать что-то вроде:

      def print_fields(message_desc):
  for field in message_desc.fields:
    if field.type == field.TYPE_MESSAGE:
      print_fields(field.message_type)
    else:
      print(field.full_name)

Затем вызовите его в дескрипторе сообщения, например:.

Другие вопросы по тегам