Protobuf 訊息

Python 用戶端程式庫的 14.0.0 版本推出了名為 use_proto_plus 的新必要設定參數,用於指定您要程式庫傳回 proto-plus 訊息protobuf 訊息。如要進一步瞭解如何設定此參數,請參閱設定文件

本節說明選擇要使用的訊息類型對效能的影響,因此建議您詳閱並瞭解各種選項,再做出明智的決定。不過,如果您想在不變更程式碼的情況下升級至 14.0.0 版,可以將 use_proto_plus 設為 True,以免破壞介面變更。

Proto-plus 與 protobuf 訊息

10.0.0 版中,Python 用戶端程式庫已遷移至新的程式碼產生器管道。這個管道整合了 proto-plus,目的是透過使其行為更像原生 Python 物件,改善 protobuf 訊息介面的人體工學。這項改善的缺點是,proto-Plus 會帶來效能負擔。

Proto Plus 效能

proto-plus 的核心優點之一,就是會透過名為類型管理的程序,將protobuf 訊息已知類型轉換為原生 Python 類型。

破壞性會發生在

syntax = "proto3";

message Dog {
  string name = 1;
}

將此定義轉換為 proto-plus 類別後,如下所示:

import proto

class Dog(proto.Message):
    name = proto.Field(proto.STRING, number=1)

接著,您可以初始化 Dog 類別並存取其 name 欄位,方法和其他 Python 物件一樣:

dog = Dog()
dog.name = "Scruffy"
print(dog.name)

讀取及設定 name 欄位時,值會從原生 Python str 類型轉換為 string 類型,以便該值與 protobuf 執行階段相容。

自版本 10.0.0 發布以來,我們進行分析時,我們發現執行這些類型轉換的時間會大幅影響效能,因此請務必為使用者提供使用 protobuf 訊息的選項。

proto-plus 和 protobuf 訊息的用途

Proto Plus 訊息用途
Proto Plus 針對 protobuf 訊息提供了多項人體工學改善,因此非常適合用於編寫可維護且容易閱讀的程式碼。這些類別會公開原生 Python 物件,因此更容易使用及理解。
Protobuf 訊息用途
針對效能有限的用途使用通訊協定緩衝區,尤其是需要快速處理大型報表的應用程式,或是需要執行大量作業的建構變更要求時,例如使用 BatchJobServiceOfflineUserDataJobService

動態變更訊息類型

為應用程式選取適當的訊息類型後,您可能會發現您需要在其他工作流程中使用其他類型的訊息。在這種情況下,您可以使用用戶端程式庫提供的公用程式,輕鬆地動態切換這兩種類型。使用上述相同的 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 相同。

附加至重複的純量欄位

在重複的純量類型欄位 (例如 stringint64 欄位) 中新增值時,無論訊息類型為何,介面都會相同:

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 Generator 模組中建構。也可以透過程式存取。

首先,請安裝模組:

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())

Issue tracker

如果對這些變更有任何疑問,或無法順利遷移至程式庫 14.0.0 版本,請透過我們的追蹤工具回報問題