Wiadomości protokołu Protobuf

Parametr konfiguracji use_proto_plus pozwala określić, czy biblioteka ma zwracać wiadomości proto-plus czy wiadomości protobuf. Szczegółowe informacje o tym, jak ustawić ten parametr, znajdziesz w dokumentacji konfiguracji.

Z tej sekcji dowiesz się, jak wybór typu wiadomości wpływa na skuteczność. Dlatego zalecamy zapoznanie się z dostępnymi opcjami, aby podjąć świadomą decyzję.

Porównanie wiadomości proto-plus i protobuf

System przetwarzania kodu integruje proto-plus, aby poprawić ergonomię interfejsu wiadomości protobuf, sprawiając, że wiadomości zachowują się bardziej jak natywne obiekty Pythona. Oznacza to jednak, że korzystanie z proto-plus powoduje wzrost obciążenia wydajności.

Skuteczność proto-plus

Jedną z głównych zalet proto-plus jest to, że konwertuje wiadomości proto-plusznane typy na natywne typy Pythona za pomocą procesu zwanego typem marshaling.

Marshalowanie występuje, gdy uzyskuje się dostęp do pola w przypadku wystąpienia wiadomości proto-plus, a w szczególności gdy pole jest odczytywane lub ustawiane, na przykład w definicji protobuf:

syntax = "proto3";

message Dog {
  string name = 1;
}

Gdy ta definicja zostanie przekształcona w klasę proto-plus, będzie wyglądać mniej więcej tak:

import proto

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

Następnie możesz zainicjować klasę Dog i uzyskać dostęp do jej pola name tak jak do dowolnego innego obiektu Pythona:

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

Podczas odczytu i ustawienia pola name wartość jest konwertowana z rodzinnego typu Pythona str na typ string, aby była zgodna z czasem wykonywania protobuf.

Na podstawie analizy wydajności stwierdziliśmy, że czas potrzebny na przeprowadzenie tego typu konwersji ma na tyle duży wpływ na wydajność, że użytkownicy powinni sami decydować, czy chcą używać wiadomości protobuf.

Przypadki użycia wiadomości proto-plus i protobuf

Przypadki użycia wiadomości proto-plus
Proto-plus oferuje szereg ulepszeń ergonomicznych w porównaniu z wiadomościami protobuf, dzięki czemu są one idealne do pisania łatwego w utrzymaniu i czytelnego kodu. Ponieważ udostępniają one natywne obiekty Pythona, są łatwiejsze w użyciu i zrozumieniu.
Zastosowania wiadomości Protobuf
Używaj protokołów protobuf w przypadkach, w których liczy się wydajność, zwłaszcza w aplikacjach, które muszą szybko przetwarzać duże raporty lub które tworzą zapytania o zmianę z dużą liczbą operacji, np. BatchJobService lub OfflineUserDataJobService.

Dynamiczna zmiana typów wiadomości

Po wybraniu odpowiedniego typu wiadomości dla aplikacji może się okazać, że w przypadku określonego procesu roboczego musisz użyć innego typu. W tym przypadku można łatwo przełączać się między tymi dwoma typami dynamicznie, korzystając z narzędzi oferowanych przez bibliotekę klienta. Przy użyciu tej samej klasy wiadomości Dog z powyższego przykładu:

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)

Różnice w interfejsie wiadomości Protobuf

Interfejs proto-plus jest szczegółowo opisany, ale tutaj wyróżniliśmy kilka kluczowych różnic, które mają wpływ na typowe przypadki użycia biblioteki klienta Google Ads.

Serializacja bajtów

Komunikaty proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
komunikaty Protobuf;
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Serializacja w formacie JSON

Komunikaty proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
komunikaty Protobuf;
from google.protobuf.json_format import MessageToJson, Parse

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

Maski pól

Metoda pomocnicza maski pola udostępniana przez api-core jest przeznaczona do używania instancji wiadomości protobuf. Dlatego, gdy używasz proto-plus, przekształcaj je w wiadomości protobuf, aby korzystać z pomocy:

Komunikaty 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)
komunikaty protokołu protobuf;
from google.api_core.protobuf_helpers import field_mask

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

Wartości w polu enum

Enumy udostępniane przez wiadomości proto-plus są instancjami natywnego typu Pythona enum, a zatem dziedziczą wiele metod ułatwiających pracę.

Pobieranie typu wyliczeniowego

Gdy używasz metody GoogleAdsClient.get_type do pobierania typów wyliczeń, zwracane komunikaty różnią się nieco w zależności od tego, czy używasz komunikatów proto-plus czy protobuf. Na przykład:

Komunikaty proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
komunikaty protokołu protobuf;
val = client.get_type("CampaignStatusEnum").PAUSED

Aby ułatwić pobieranie typów, w przypadku instancji GoogleAdsClient jest dostępny atrybuty ułatwiający, który ma spójny interfejs niezależnie od tego, którego typu wiadomości używasz:

val = client.enums.CampaignStatusEnum.PAUSED

Pobieranie wartości typu wyliczeniowego

Czasami przydatna jest wartość lub identyfikator pola danego wyliczenia. Na przykład PAUSED w polu CampaignStatusEnum odpowiada 3:

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

Pobieranie nazwy typu wyliczeniowego

Czasami warto znać nazwę pola typu enum. Na przykład podczas odczytywania obiektów z interfejsu API możesz chcieć wiedzieć, któremu stanowi kampanii odpowiada wartość int 3:

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

Pola powtarzane

Jak opisano w dokumentacji proto-plus, pola powtarzające się są zazwyczaj równoważne z listami wpisów, co oznacza, że zachowują się prawie tak samo jak list.

Dołączanie wartości do powtarzających się pól skalarnych

Podczas dodawania wartości do powtarzanych pól skalowania, np. pól string lub int64, interfejs jest taki sam niezależnie od typu wiadomości:

Komunikaty proto-plus
ad.final_urls.append("https://www.example.com")
komunikaty Protobuf;
ad.final_urls.append("https://www.example.com")

Obejmuje to wszystkie inne typowe metody list, np. extend:

Komunikaty proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
komunikaty Protobuf;
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

Dołączanie typów wiadomości do pól powtarzalnych

Jeśli powtarzane pole nie jest polem typu skalarnego, jego dodawanie do powtarzanych pól działa nieco inaczej:

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

Przypisywanie pól powtarzalnych

W przypadku zarówno skalarnych, jak i nieskalarnych pól powtarzalnych możesz przypisywać do nich listy na różne sposoby:

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

puste wiadomości;

Czasami przydaje się wiedzieć, czy instancja wiadomości zawiera jakieś informacje lub czy ma ustawione jakieś pola.

Komunikaty proto-plus
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
komunikaty protokołu protobuf;
is_empty = campaign.ByteSize() == 0

Treść wiadomości

W przypadku wiadomości proto-plus i protobuf zalecamy użycie metody pomocniczej copy_from w GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Puste pola wiadomości

Proces ustawiania pustych pól wiadomości jest taki sam niezależnie od używanego typu wiadomości. Wystarczy, że skopiujesz pustą wiadomość do odpowiedniego pola. Zapoznaj się z sekcją Kopia wiadomości oraz z poradnikiem dotyczącym pustych pól wiadomości. Oto przykład ustawienia pustego pola wiadomości:

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

nazwy pól, które są zastrzeżonymi słowami;

Jeśli używasz wiadomości proto-plus, nazwy pól są automatycznie wyświetlane z podkreśleniem na końcu, jeśli nazwa jest też słowem zarezerwowanym w Pythonie. Oto przykład pracy z instancją Asset:

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

Pełna lista nazw zastrzeżonych jest tworzona w module gapicgenerator. Dostęp do niego można uzyskać automatycznie.

Najpierw zainstaluj moduł:

python -m pip install gapic-generator

Następnie w replu lub skrypcie Pythona:

import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)

Obecność w polu

Pola w instancjach wiadomości protobuf mają wartości domyślne, więc nie zawsze łatwo jest stwierdzić, czy dane pole zostało ustawione.

Komunikaty proto-plus
# Use the "in" operator.
has_field = "name" in campaign
komunikaty protokołu protobuf;
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

Interfejs klasy protobufMessage ma metodę HasField, która określa, czy pole w wiadomości zostało ustawione, nawet jeśli ma wartość domyślną.

Metody wiadomości Protobuf

Interfejs wiadomości protobuf zawiera kilka metod ułatwiających, które nie są częścią interfejsu proto-plus. Można jednak uzyskać do nich dostęp, konwertując wiadomość proto-plus na jej odpowiednik w formacie 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())

Śledzenie problemów

Jeśli masz pytania dotyczące tych zmian lub problemy z przeniesieniem do najnowszej wersji biblioteki, zgłoś problem w naszym systemie śledzenia błędów.