Protobuf-Nachrichten

Mit dem Konfigurationsparameter use_proto_plus können Sie angeben, ob die Bibliothek proto-plus-Nachrichten oder Protobuf-Nachrichten zurückgeben soll. Weitere Informationen zum Festlegen dieses Parameters finden Sie in der Konfigurationsdokumentation.

In diesem Abschnitt werden die Auswirkungen der einzelnen Optionen auf die Leistung beschrieben, damit Sie den besten Ansatz für Ihre Anwendung auswählen können.

Proto-plus-Nachrichten im Vergleich zu Protokollpuffer-Nachrichten

Die Pipeline für die Code-Generierung integriert proto-plus, um die Ergonomie der Protobuf-Nachrichtenschnittstelle zu verbessern, indem sie sich eher wie Standard-Python-Objekte verhält. Die Verwendung von proto-plus führt jedoch zu einem Leistungsaufwand.

Leistung von Proto-Plus

Einer der Hauptvorteile von proto-plus ist, dass Protobuf-Nachrichten und bekannte Typen durch einen Prozess namens Typ-Marshaling in integrierte Python-Typen konvertiert werden.

Das Marshaling erfolgt, wenn auf ein Feld in einer Proto-Plus-Nachrichteninstanz zugegriffen wird, insbesondere wenn ein Feld gelesen oder festgelegt wird, z. B. in einer Protobuf-Definition:

syntax = "proto3";

message Dog {
  string name = 1;
}

Wenn diese Definition in eine proto-plus-Klasse konvertiert wird, sieht sie so aus:

import proto


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

Anschließend können Sie die Dog-Klasse initialisieren und auf ihr name-Feld zugreifen, wie bei jedem anderen Python-Objekt:

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

Beim Lesen und Festlegen des Felds name wird der Wert vom integrierten Python-Typ str in den Typ string konvertiert, damit der Wert mit der Protobuf-Laufzeit kompatibel ist.

Die für diese Typkonvertierungen benötigte Zeit hat einen so großen Einfluss auf die Leistung, dass Sie je nach den Anforderungen Ihrer Anwendung entscheiden sollten, ob Sie Proto-Plus- oder Protobuf-Nachrichten verwenden.

Anwendungsfälle für proto-plus- und Protobuf-Nachrichten

Anwendungsfälle für Proto-Plus-Nachrichten
Proto-plus bietet eine Reihe ergonomischer Verbesserungen gegenüber Protobuf-Nachrichten und eignet sich daher ideal zum Schreiben von wartungsfreundlichem, lesbarem Code. Da sie Standard-Python-Objekte verfügbar machen, sind sie einfacher zu verwenden und zu verstehen.
Anwendungsfälle für Protobuf-Nachrichten
Verwenden Sie Protobufs für leistungsintensive Anwendungsfälle, insbesondere in Apps, die große Berichte schnell verarbeiten oder Mutate-Anfragen mit einer großen Anzahl von Vorgängen erstellen müssen, z. B. mit BatchJobService oder OfflineUserDataJobService.

Nachrichtentypen dynamisch wechseln

Nachdem Sie den geeigneten Nachrichtentyp für Ihre App ausgewählt haben, stellen Sie möglicherweise fest, dass Sie für einen bestimmten Workflow den anderen Typ verwenden müssen. In diesem Fall können Sie mithilfe von Dienstprogrammen, die von der Clientbibliothek bereitgestellt werden, dynamisch zwischen den beiden Typen wechseln. Wir verwenden dieselbe Dog-Nachrichtenklasse wie zuvor:

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)

Unterschiede bei der Protobuf-Nachrichtenschnittstelle

Die proto-plus-Schnittstelle ist detailliert dokumentiert. In den folgenden Abschnitten werden die wichtigsten Unterschiede hervorgehoben, die sich auf gängige Anwendungsfälle für die Google Ads-Clientbibliothek auswirken.

Serialisierung von Byte

Proto-plus-Nachrichten
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Protobuf-Nachrichten
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

JSON-Serialisierung

Proto-plus-Nachrichten
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Protobuf-Nachrichten
from google.protobuf.json_format import MessageToJson, Parse

serialized = MessageToJson(campaign)
deserialized = Parse(serialized, campaign)

Feldmasken

Die von api-core bereitgestellte Hilfsmethode für Feldmasken ist für die Verwendung von Protobuf-Nachrichteninstanzen konzipiert. Wenn Sie proto-plus-Nachrichten verwenden, müssen Sie sie in Protobuf-Nachrichten umwandeln, um den Helfer zu verwenden:

Proto-plus-Nachrichten
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-Nachrichten
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
mask = field_mask(None, campaign)

Enums

Enums, die von proto-plus-Nachrichten bereitgestellt werden, sind Instanzen des integrierten Python-Typs enum und erben daher eine Reihe von praktischen Methoden.

Abrufen des Enum-Typs

Wenn Sie die Methode GoogleAdsClient.get_type zum Abrufen von Enums verwenden, unterscheiden sich die zurückgegebenen Meldungen geringfügig, je nachdem, ob Sie Proto-Plus- oder Protobuf-Meldungen verwenden. Beispiel:

Proto-plus-Nachrichten
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Protobuf-Nachrichten
val = client.get_type("CampaignStatusEnum").PAUSED

Um das Abrufen von Enums zu vereinfachen, gibt es ein Convenience-Attribut für GoogleAdsClient-Instanzen, das unabhängig vom verwendeten Nachrichtentyp eine konsistente Schnittstelle hat:

val = client.enums.CampaignStatusEnum.PAUSED

Abrufen von Enum-Werten

Manchmal ist es nützlich, den Wert oder die Feld-ID eines bestimmten Enums zu kennen. Beispiel: PAUSED für CampaignStatusEnum entspricht 3:

Proto-plus-Nachrichten
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
Protobuf-Nachrichten
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"))

Abrufen von Enum-Namen

Manchmal ist es nützlich, den Namen eines Enum-Felds zu kennen. Wenn Sie beispielsweise Objekte aus der API lesen, möchten Sie möglicherweise wissen, welchem Kampagnenstatus die Ganzzahl 3 entspricht:

Proto-plus-Nachrichten
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
Protobuf-Nachrichten
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))

Wiederkehrende Felder

Wie in der proto-plus-Dokumentation beschrieben, entsprechen wiederholte Felder im Allgemeinen typisierten Listen, d. h., sie verhalten sich fast identisch wie ein list.

Werte an wiederholte skalare Felder anhängen

Wenn Sie Werte für Felder vom Typ Skalar mit Wiederholung hinzufügen, z. B. für die Felder string oder int64, ist die Benutzeroberfläche unabhängig vom Nachrichtentyp gleich:

Proto-plus-Nachrichten
ad.final_urls.append("https://www.example.com")
Protobuf-Nachrichten
ad.final_urls.append("https://www.example.com")

Dazu gehören auch alle anderen gängigen list-Methoden, z. B. extend:

Proto-plus-Nachrichten
ad.final_urls.extend(
    ["https://www.example.com", "https://www.example.com/2"]
)
Protobuf-Nachrichten
ad.final_urls.extend(
    ["https://www.example.com", "https://www.example.com/2"]
)

Nachrichtentypen an wiederholte Felder anhängen

Wenn das wiederholte Feld kein Skalartyp ist, ist das Verhalten beim Hinzufügen zu wiederholten Feldern etwas anders:

Proto-plus-Nachrichten
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Protobuf-Nachrichten
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

Wiederkehrende Felder zuweisen

Sowohl für skalare als auch für nicht skalare wiederkehrende Felder können Sie dem Feld Listen auf verschiedene Arten zuweisen:

Proto-plus-Nachrichten
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Protobuf-Nachrichten
# 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

Leere Nachrichten

Manchmal ist es nützlich zu wissen, ob eine Nachrichteninstanz Informationen enthält oder ob Felder festgelegt sind.

Proto-plus-Nachrichten
# When using proto-plus messages you can check the message for truthiness.
is_empty = not bool(campaign)
Protobuf-Nachrichten
is_empty = campaign.ByteSize() == 0

Nachrichtenkopie

Verwenden Sie für proto-plus- und protobuf-Nachrichten die Hilfsmethode copy_from für GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Leere Nachrichtenfelder

Das Verfahren zum Festlegen leerer Nachrichtenfelder ist unabhängig vom verwendeten Nachrichtentyp. Sie kopieren eine leere Nachricht in das entsprechende Feld. Weitere Informationen finden Sie im Abschnitt Nachrichtentext sowie im Leitfaden Leere Nachrichtenfelder. Das folgende Beispiel zeigt, wie Sie ein leeres Nachrichtenfeld festlegen:

client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))

Feldnamen, die reservierte Wörter sind

Wenn Sie proto-plus-Nachrichten verwenden, werden Feldnamen automatisch mit einem nachgestellten Unterstrich angezeigt, wenn der Name auch ein reserviertes Wort in Python ist. Das folgende Beispiel zeigt, wie Sie mit einer Asset-Instanz arbeiten:

asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE

Die vollständige Liste der reservierten Namen wird im Modul GAPIC-Generator erstellt. Der Zugriff ist auch programmatisch möglich.

Installieren Sie zuerst das Modul:

python -m pip install gapic-generator

Gehen Sie dann in einer Python-REPL oder einem Python-Script so vor:

import gapic.utils

print(gapic.utils.reserved_names.RESERVED_NAMES)

Feldpräsenz

Da die Felder in Protobuf-Nachrichteninstanzen Standardwerte haben, ist es nicht immer intuitiv zu wissen, ob ein Feld festgelegt wurde oder nicht.

Proto-plus-Nachrichten
# Use the "in" operator.
has_field = "name" in campaign
Protobuf-Nachrichten
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

Die Protobuf-Klassenschnittstelle Message hat eine HasField-Methode, mit der ermittelt wird, ob eine Unternachricht, ein oneof-Feld oder ein skalierbares optional-Feld in einer Nachricht festgelegt wurde, auch wenn es auf einen Standardwert gesetzt wurde. Wenn Sie HasField für nicht optionale skalare Felder in proto3 aufrufen, wird ein ValueError ausgelöst.

Protobuf-Nachrichtenmethoden

Die Protobuf-Nachrichtenschnittstelle enthält einige Hilfsmethoden, die nicht Teil der Proto-Plus-Schnittstelle sind. Sie können jedoch darauf zugreifen, indem Sie eine Proto-Plus-Nachricht in das entsprechende Protobuf-Objekt konvertieren:

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

Problemverfolgung

Wenn Sie Fragen zu diesen Änderungen haben oder Probleme bei der Migration zur neuesten Version der Bibliothek auftreten, melden Sie ein Problem im Issue Tracker.