如果我想向协议缓冲区中的字段添加一个在编译时未知的值,我目前正在做
setattr
我通常不喜欢使用
setattr
,因为它看起来不太安全。但是当我知道该对象是 protobuf 时,我认为这很好,因为我设置它的值必须是 protobuf 允许的类型。所以也许它并不是真的不安全?
让我举例说明。 首先,假设我有这个 protobuf:
message Person {
string first_name = 1;
string second_name = 1;
int age = 3;
}
然后我有一些使用上面的 protobuf 的代码:
from person_pb2 import Person
my_info = {"first_name": "Mike", "last_name": "example", "age": 999}
me = Person()
for field, value in my_info:
setattr(me, field, value)
这是处理 protobuf 的一种非常灵活的方式。例如,我不能像在
dict
中那样指定它,说
me[field] = value
然而,
me[field] = value
是绝对安全的。如果使用
setattr
时字段/属性的值类型错误,我会收到错误:
TypeError: bad argument type for built-in operation
因此,我很想说,对于 protobufs,使用
setattr
完全没问题,并且,事实上,这确实是以编程方式向 protobuf 字段添加值的唯一方法。它是否正确?有更好或更安全的方法吗? 我不能做类似
me.first_name = "Mike"
的事情,因为我需要它是程序化的。
你问了关于在 Python 中使用
setattr
处理 protobuf 的问题,特别是关于它是否是处理它们的安全且首选方式。你对
setattr
的谨慎是值得赞赏的,因为它在处理不受信任的输入时确实会带来安全风险,但你说的对,在 protobuf 的上下文中,它通常是可以接受的。
为什么
setattr
在这里可以接受
-
类型安全:
Protobuf 强制执行严格的类型检查。如果你尝试使用错误类型的
setattr
设置字段,protobuf 库将在运行时引发错误。这减轻了与setattr
相关的常见安全问题之一,即设置错误类型的属性。 -
灵活性:
如你所述,
setattr
在程序化地填充 protobuf 时提供了灵活性,尤其是在字段名称在运行时才知道的情况下。
代码示例
你的代码示例很好地展示了如何在 protobuf 的上下文中安全地使用
setattr
。
from person_pb2 import Person
my_info = {"first_name": "Mike", "last_name": "example", "age": 999}
me = Person()
for field, value in my_info.items(): # 使用 .items() 迭代字典
setattr(me, field, value)
替代方案和最佳实践
尽管
setattr
在这种情况下可以接受,但请考虑以下替代方案和最佳实践:
-
MessageToDict
和ParseDict
: Protobuf 库提供了MessageToDict
和ParseDict
函数,这些函数允许你在字典和 protobuf 消息之间进行转换。如果你的数据最初是字典格式,则此方法可能更干净且更易于阅读。
```python from google.protobuf.json_format import MessageToDict, ParseDict
my_info = {"first_name": "Mike", "last_name": "example", "age": 999} me = ParseDict(my_info, Person()) ```
-
HasField
进行条件设置: 如果你需要有条件地设置字段,请使用HasField
方法来检查该字段是否已设置,尤其是在使用重复字段或可选字段时。
python
if not me.HasField("first_name"):
setattr(me, "first_name", "Mike")
- 验证: 始终验证来自不受信任来源的数据,即使在使用 protobuf 时也是如此。Protobuf 确保类型安全,但不一定确保数据有效性。
结论
简而言之,在处理 protobuf 时,在动态设置字段时,
setattr
是一个可接受且经常使用的工具。只要你确信正在处理的数据是类型安全的,你就可以在代码中自信地使用它。但是,请探索 protobuf 库提供的替代方法,例如
MessageToDict
和
ParseDict
,以获得更具可读性和 Python 风格的代码。