web-dev-qa-db-ja.com

Pythonのプロトコルバッファ属性をループする

プロトコルバッファメッセージに含まれるすべての属性/サブオブジェクトを再帰的にループするのを手伝ってもらいたいのですが、それらの名前や数がわからないと仮定します。

例として、Googleウェブサイトのチュートリアルから次の.protoファイルを取得します。

  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 = "[email protected]"
phone = person.phone.add()
phone.number = "555-4321"
phone.type = tutorial.Person.HOME

Personが与えられた場合、属性の名前と各要素の値の両方にアクセスするにはどうすればよいですか:person.idperson.nameperson.emailperson.phone.numberperson.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は「name」を教えてくれますが、どうすれば「johndoe」を取得できますか?

17
Toby Wilkins

私はprotobufsにあまり詳しくないので、この種のことにはもっと簡単な方法やAPIがあるかもしれません。ただし、以下に、フィールドを反復/イントロスペクトして出力する方法の例を示します。うまくいけば、少なくとも正しい方向に進むのに十分です...

import addressbook_pb2 as addressbook

person = addressbook.Person(id=1234, name="John Doe", email="[email protected]")
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: [email protected]
tutorial.Person.PhoneNumber.number: 1234567890
tutorial.Person.PhoneNumber.type: HOME
30
Jacob Burbach