私はそのような.proto
ファイルを持っています
syntax = "proto3";
import "google/protobuf/any.proto";
message Request {
google.protobuf.Any request_parameters = 1;
}
Request
オブジェクトを作成し、そのフィールドにデータを入力するにはどうすればよいですか?私はこれを試しました:
import ma_pb2
from google.protobuf.any_pb2 import Any
parameters = {"a": 1, "b": 2}
Request = ma_pb2.Request()
some_any = Any()
some_any.CopyFrom(parameters)
Request.request_parameters = some_any
しかし、私にはエラーがあります:
TypeError: Parameter to CopyFrom() must be instance of same class: expected google.protobuf.Any got dict.
[〜#〜]更新[〜#〜]
@Kevinのプロンプトに従って、.proto
ファイルに新しいメッセージを追加しました。
message Small {
string a = 1;
}
これで、コードは次のようになります。
Request = ma_pb2.Request()
small = ma_pb2.Small()
small.a = "1"
some_any = Any()
some_any.Pack(small)
Request.request_parameters = small
しかし、最後の割り当てでエラーが発生しました:
Request.request_parameters = small
AttributeError: Assignment not allowed to field "request_parameters" in protocol message object.
私は何を間違えましたか?
Any
は、任意のキーと値を格納するためのマジックボックスではありません。 Any
の目的は、実行時まで使用するメッセージがわからない場合に、 「任意の」メッセージタイプを示す にすることです。ただし、実行時には、特定のメッセージを念頭に置く必要があります。次に、 .Pack()
および.Unpack()
メソッドを使用 でそのメッセージをAny
に変換し、その時点であなたは Request.request_parameters.CopyFrom(some_any)
のようなことをするでしょう。
したがって、この特定の辞書を保存する場合は、次のようにします。
{"a": 1, "b": 2}
... a
およびb
という名前の整数フィールドを持つメッセージタイプを記述した.proto
ファイルが必要です。個人的には、それはやり過ぎだと思います。 a
フィールドとb
フィールドを分離する正当な理由がない限り、Request
メッセージに直接スローするだけです。これらのキーの1つを「忘れた」場合、 後でいつでも追加できます なので、完全性についてあまり心配する必要はありません。
上記で説明したものではなく、「任意のキーと値を格納するためのマジックボックス」が本当に必要な場合は、Any
の代わりに Map を使用できます。これには、キーのセットに任意の文字列(HTTPヘッダーなど)が含まれている可能性がある場合に、すべてのキーを事前に宣言する必要がないという利点があります。属性よりも文字列のスペルを間違えやすいため、リントや型チェックが難しいという欠点があります(特に静的に型付けされた言語で)。リンクされたリソースに示されているように、マップは基本的に次のような繰り返しフィールドの構文糖衣です(つまり、オンワイヤ表現はこれを行うことで得られるものとまったく同じであるため、そうでないクライアントとの下位互換性がありますマップをサポートしていません):
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = N;