借助 use_proto_plus
配置参数,您可以指定希望库返回 proto-plus 消息还是 protobuf 消息。如需详细了解如何设置此参数,请参阅配置文档。
本部分介绍了选择使用哪些类型的消息对性能的影响,因此我们建议您阅读并了解这些选项,以便做出明智的决定。
Proto-plus 与 protobuf 消息
代码生成器流水线集成了 proto-plus,以便通过使 protobuf 消息接口的行为更像原生 Python 对象来改进 protobuf 消息接口的人体工学。不过,这意味着使用 proto-plus 会引入性能开销。
Proto-plus 性能
Proto-plus 的一个核心优势是,它可以通过称为“类型封装”的流程将 protobuf 消息和已知类型转换为原生 Python 类型。
在 proto-plus 消息实例上访问字段时会发生封装,具体而言,就是在读取或设置字段时(例如在 protobuf 定义中)发生封装:
syntax = "proto3";
message Dog {
string name = 1;
}
将此定义转换为 proto-plus 类后,它将如下所示:
import proto
class Dog(proto.Message):
name = proto.Field(proto.STRING, number=1)
然后,您可以像访问任何其他 Python 对象一样初始化 Dog
类并访问其 name
字段:
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
读取和设置 name
字段时,系统会将值从原生 Python str
类型转换为 string
类型,以便该值与 protobuf 运行时兼容。
根据我们的性能分析,我们确定执行此类转换所花费的时间对性能有足够大的影响,因此用户应根据自己的需求决定是否使用 protobuf 消息。
proto-plus 和 protobuf 消息的用例
- Proto-plus 消息用例
- Proto-plus 在人体工学方面比 protobuf 消息进行了许多改进,因此非常适合编写可维护且可读的代码。由于它们会公开原生 Python 对象,因此更易于使用和理解。
- Protobuf 消息用例
- 对于对性能敏感的用例,请使用 protobuf,尤其是在需要快速处理大型报告或使用大量操作(例如使用
BatchJobService
或OfflineUserDataJobService
)构建更改请求的应用中。
动态更改消息类型
为应用选择合适的消息类型后,您可能会发现需要针对特定工作流使用其他类型。在这种情况下,您可以使用客户端库提供的实用程序在两种类型之间轻松切换。使用上面的 Dog
消息类:
from google.ads.googleads import util
# Proto-plus message type
dog = Dog()
# Protobuf message type
dog = util.convert_proto_plus_to_protobuf(dog)
# Back to proto-plus message type
dog = util.convert_protobuf_to_proto_plus(dog)
protobuf 消息接口差异
我们详细记录了 proto-plus 接口,但在此处将重点介绍一些会影响 Google Ads 客户端库常见用例的一些关键差异。
字节序列化
- Proto-plus 消息
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Protobuf 消息
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
JSON 序列化
- Proto-plus 消息
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Protobuf 消息
from google.protobuf.json_format import MessageToJson, Parse serialized = MessageToJson(campaign) deserialized = Parse(serialized, campaign)
字段掩码
api-core 提供的字段掩码辅助方法旨在使用 protobuf 消息实例。因此,使用 proto-plus 消息时,请将其转换为 protobuf 消息以使用该帮助程序:
- Proto-plus 消息
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign) mask = field_mask(None, protobuf_campaign)
- Protobuf 消息
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
枚举
proto-plus 消息公开的枚举是 Python 原生 enum
类型的实例,因此会继承多种便捷方法。
枚举类型检索
使用 GoogleAdsClient.get_type
方法检索枚举时,返回的消息会略有不同,具体取决于您使用的是 proto-plus 消息还是 protobuf 消息。例如:
- Proto-plus 消息
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Protobuf 消息
val = client.get_type("CampaignStatusEnum").PAUSED
为了简化枚举的检索,GoogleAdsClient
实例上有一个便捷属性,无论您使用哪种消息类型,该属性的接口都是一致的:
val = client.enums.CampaignStatusEnum.PAUSED
枚举值检索
有时,了解给定枚举的值或字段 ID 会很有用,例如,CampaignStatusEnum
上的 PAUSED
对应于 3
:
- Proto-plus 消息
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the value of campaign status print(campaign.status.value)
- Protobuf 消息
campaign = client.get_type("Campaign") status_enum = client.enums.CampaignStatusEnum campaign.status = status_enum.PAUSED # To read the value of campaign status print(status_enum.CampaignStatus.Value(campaign.status))
枚举名称检索
有时,了解枚举字段的名称会很有用。例如,从 API 读取对象时,您可能需要知道整数 3
对应的广告系列状态:
- Proto-plus 消息
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the name of campaign status print(campaign.status.name)
- Protobuf 消息
campaign = client.get_type("Campaign") status_enum = client.enums.CampaignStatusEnum # Sets the campaign status to the int value for PAUSED campaign.status = status_enum.PAUSED # To read the name of campaign status status_enum.CampaignStatus.Name(campaign.status)
重复字段
如 proto-plus 文档中所述,重复字段通常等同于类型化列表,这意味着它们的行为与 list
几乎完全相同。
将值附加到重复的标量字段
向重复的标量类型字段(例如 string
或 int64
字段)添加值时,无论消息类型如何,界面都是相同的:
- Proto-plus 消息
ad.final_urls.append("https://www.example.com")
- Protobuf 消息
ad.final_urls.append("https://www.example.com")
这也包括所有其他常见的 list
方法,例如 extend
:
- Proto-plus 消息
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Protobuf 消息
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
将消息类型附加到重复字段
如果重复字段不是标量类型,将其添加到重复字段时的行为会略有不同:
- Proto-plus 消息
frequency_cap = client.get_type("FrequencyCapEntry") frequency_cap.cap = 100 campaign.frequency_caps.append(frequency_cap)
- Protobuf 消息
# The add method initializes a message and adds it to the repeated field frequency_cap = campaign.frequency_caps.add() frequency_cap.cap = 100
分配重复字段
对于标量和非标量重复字段,您可以通过不同的方式向字段分配列表:
- Proto-plus 消息
# In proto-plus it's possible to use assignment. urls = ["https://www.example.com"] ad.final_urls = urls
- Protobuf 消息
# Protobuf messages do not allow assignment, but you can replace the # existing list using slice syntax. urls = ["https://www.example.com"] ad.final_urls[:] = urls
空白消息
有时,了解消息实例是否包含任何信息或是否设置了任何字段非常有用。
- Proto-plus 消息
# When using proto-plus messages you can simply check the message for # truthiness. is_empty = bool(campaign) is_empty = not campaign
- Protobuf 消息
is_empty = campaign.ByteSize() == 0
广告内容/文案
对于 proto-plus 和 protobuf 消息,我们都建议对 GoogleAdsClient
使用 copy_from
辅助方法:
client.copy_from(campaign, other_campaign)
消息字段为空
无论您使用哪种消息类型,设置空消息字段的过程都是相同的。您只需将空白消息复制到相关字段即可。请参阅邮件副本部分以及空邮件字段指南。下面是一个设置空消息字段的示例:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
字段名称是保留字词
使用 proto-plus 消息时,如果字段名称也是 Python 中的保留字,则字段名称会自动带有尾随下划线。下面是一个使用 Asset
实例的示例:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
预留名称的完整列表是在 gapic 生成器模块中构建的。您也可以通过编程方式访问它。
首先,安装该模块:
python -m pip install gapic-generator
然后,在 Python REPL 或脚本中执行以下操作:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
现场支持
由于 protobuf 消息实例中的字段具有默认值,因此并非总能直观地了解某个字段是否已设置。
- Proto-plus 消息
# Use the "in" operator. has_field = "name" in campaign
- Protobuf 消息
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
protobuf Message
类接口有一个 HasField
方法,用于确定消息中的字段是否已设置,即使已设置为默认值也是如此。
protobuf 消息方法
protobuf 消息接口包含一些不属于 proto-plus 接口的便捷方法;不过,只需将 proto-plus 消息转换为其 protobuf 对应项,即可轻松访问这些方法:
# Accessing the ListFields method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.ListFields())
# Accessing the Clear method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.Clear())
问题跟踪器
如果您对这些变更有任何疑问,或者在迁移到最新版本的库时遇到任何问题,请在我们的跟踪器中提交问题。