2015-05-09 129 views
11

通常,我有一個protobuf定義,它使用了Python關鍵字「from」。它在Java/C#/ C++中工作,但是當涉及到Python時,我無法爲其分配值。保留關鍵字用於Python中的protobuf

這是我的問題的細節。

我有一個protobuf的定義如下面:

message Foo 
{ 
    required int64 from = 10 
    ... 
} 

由於場「從」是在Python關鍵字,後我生成的Python代碼,我無法編譯如下的代碼:

foo = Foo() 
foo.from = 1234 

於是,我試圖用SETATTR()來設置該屬性:

setattr(foo, 'from', 1234) 

這給了我一個例外的Protobuf:

AttributeError: Assignment not allowed to composite field "from" in protocol message object. 

我不能在這一刻,因爲它已經在系統中廣泛應用改變了定義。如果我可以解決在Python中使用「from」屬性的任何幫助,我們將不勝感激。

下面是protobuf的生成的代碼:

import sys 


_FOO = _descriptor.Descriptor(
    name='Foo', 
    full_name='com.kerneljoy.Foo', 
    filename=None, 
    file=DESCRIPTOR, 
    containing_type=None, 
    fields=[ 
    _descriptor.FieldDescriptor(
     name='from', full_name='com.kerneljoy.Foo.from', index=0, 
     number=10, type=3, cpp_type=2, label=2, 
     has_default_value=False, default_value=0, 
     message_type=None, enum_type=None, containing_type=None, 
     is_extension=False, extension_scope=None, 
     options=None), 
    ], 
    extensions=[ 
    ], 
    nested_types=[], 
    enum_types=[ 
    ], 
    options=None, 
    is_extendable=False, 
    extension_ranges=[], 
    oneofs=[ 
    ], 
    serialized_start=28, 
    serialized_end=47, 
) 

DESCRIPTOR.message_types_by_name['Foo'] = _FOO 

Foo = _reflection.GeneratedProtocolMessageType('Foo', (_message.Message,), dict(
    DESCRIPTOR = _FOO, 
    __module__ = 'Foo_pb2' 
    # @@protoc_insertion_point(class_scope:com.kerneljoy.Foo) 
)) 
_sym_db.RegisterMessage(Foo) 
+1

我以前從未使用協議緩衝區,但在Python中常見的成語是貼上如果您想將其用作標識符,則強調爲保留字。也許Python的實現可以做同樣的事情? 'foo = Foo(); foo.from_ = 1234'。 – chepner

+0

有趣的問題。您能否發佈protobuf生成的Python代碼?或者從一些最小的工作例子中,如果你不能發表原文。 – Unapiedra

+0

@chepner謝謝!我也試過這個。但似乎不起作用。它會報告from_未定義的錯誤。 – kerneljoy

回答

4

幾次嘗試後,我發現了SETATTR()和GETATTR()可以解決此。因爲在我的生產代碼中,'from'是指另一個protobuff定義。所以這裏的解決方案如下:

foo = Foo() 
object = getattr(foo, 'from') 
object.bar = 'value' 
object.bar2 = 'value2' 
+0

很感謝,很好的工作!很好奇這個解決方案是什麼。 –

0

實現「HasField」但不配對「GetField」很奇怪。請考慮又一實現:

def msg_GetField(msg, name, default_value=None, raise_on_not_exist=True): 
    result = default_value 
    # 
    exist = False 
    items = msg.ListFields() 
    for desc, value in items: 
     if name == desc.name: 
      result = value 
      exist = True 
    # 
    if raise_on_not_exist: 
     if not exist: 
      raise ValueError('No property') 
    # 
    return result 

您可以使用它作爲實用方法,或混入,如果你知道該怎麼做。

0

如果「from」是一個原始變量(不是複合)。設置屬性將起作用(您可以在錯誤消息中看到:「AttributeError:不允許分配到複合字段」) - 但如果Foo包含在其他對象中,則需要使用「MergeFrom」插入Foo插入它變成包含對象。

例如:

PB:

message Foo 
{ 
    required int64 from = 1 
} 
message Bar 
{ 
    required Foo foo = 1 
} 

下面的代碼應該工作:

foo=Foo() 
bar=Bar() 
setattr(foo, 'from', 1204) 
bar.MergeFrom(foo)