use_proto_plus 構成パラメータを使用すると、ライブラリが proto-plus メッセージを返すか、protobuf メッセージを返すかを指定できます。このパラメータの設定方法については、構成ドキュメントをご覧ください。
このセクションでは、各オプションのパフォーマンスへの影響について説明します。これにより、アプリケーションに最適なアプローチを選択できます。
proto-plus メッセージと protobuf メッセージ
コード生成パイプラインは、proto-plus を統合して、protobuf メッセージ インターフェースのエルゴノミクスを改善し、標準の Python オブジェクトのように動作させます。ただし、proto-plus を使用すると、パフォーマンス オーバーヘッドが発生します。
proto-plus のパフォーマンス
proto-plus の主なメリットの 1 つは、型マーシャリングと呼ばれるプロセスを通じて、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)
その後、Dog クラスを初期化し、他の Python オブジェクトと同様に name フィールドにアクセスできます。
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
name フィールドを読み取って設定すると、値が組み込みの Python str 型から string 型に変換され、値が protobuf ランタイムと互換性を持つようになります。
これらの型変換の実行に費やされる時間は、パフォーマンスに大きな影響を与えるため、アプリケーションのニーズに基づいて、proto-plus メッセージと protobuf メッセージのどちらを使用するかを決定する必要があります。
proto-plus メッセージと protobuf メッセージのユースケース
- proto-plus メッセージのユースケース
- Proto-plus は、protobuf メッセージよりも人間工学的に改善されているため、保守可能で読みやすいコードを作成するのに最適です。標準の Python オブジェクトを公開するため、使いやすく、理解しやすいです。
- Protobuf メッセージのユースケース
- パフォーマンスが重視されるユースケースでは、protobuf を使用します。具体的には、大規模なレポートを迅速に処理する必要があるアプリや、
BatchJobServiceやOfflineUserDataJobServiceなど、多数のオペレーションを含む変更リクエストを作成するアプリで使用します。
メッセージ タイプを動的に切り替える
アプリに適したメッセージ タイプを選択した後、特定のワークフローに別のタイプを使用する必要があることが判明する場合があります。この場合、クライアント ライブラリが提供するユーティリティを使用して、2 つのタイプを動的に切り替えることができます。先ほどの 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 広告クライアント ライブラリの一般的なユースケースに影響する主な違いについて説明します。
バイトのシリアル化
- 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 # Native protobuf enum fields already store the integer value (3): print(campaign.status) # Or look up the integer value from the enum name string: print(status_enum.CampaignStatus.Value("PAUSED"))
列挙型の名前の取得
列挙型フィールドの名前を知っておくと便利な場合があります。たとえば、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 print(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")
これには、extend などの他の一般的な list メソッドもすべて含まれます。
- 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 check the message for truthiness. is_empty = not bool(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 クラス インターフェースには、メッセージのサブメッセージ、oneof フィールド、または optional スカラー フィールドが設定されているかどうかを判断する HasField メソッドがあります。これは、デフォルト値に設定されている場合でも同様です。(proto3 のオプションでないスカラー フィールドで HasField を呼び出すと、ValueError が発生します)。
Protobuf メッセージ メソッド
protobuf メッセージ インターフェースには、proto-plus インターフェースの一部ではない便利なメソッドがいくつか含まれています。ただし、proto-plus メッセージを対応する protobuf に変換することで、これらのメソッドにアクセスできます。
# Accessing the ListFields method
protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign)
print(protobuf_campaign.ListFields())
# Accessing the Clear method
protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign)
protobuf_campaign.Clear()
Issue Tracker
これらの変更についてご不明な点がある場合や、最新バージョンのライブラリへの移行で問題が発生した場合は、Issue Tracker で問題を報告してください。