Komunikaty protobuf

Za pomocą parametru konfiguracji use_proto_plus możesz określić, czy biblioteka ma zwracać wiadomości proto-plus czy wiadomości protobuf. Szczegółowe informacje o ustawianiu tego parametru znajdziesz w dokumentacji konfiguracji.

W tej sekcji opisujemy wpływ każdej opcji na wydajność, aby ułatwić Ci wybór najlepszego rozwiązania dla Twojej aplikacji.

Komunikaty Proto-plus a komunikaty protobuf

Potok generatora kodu integruje proto-plus, aby poprawić ergonomię interfejsu wiadomości protobuf, dzięki czemu zachowują się one bardziej jak standardowe obiekty Pythona. Oznacza to jednak, że używanie proto-plus powoduje dodatkowe obciążenie wydajności.

Wydajność Proto-plus

Jedną z głównych zalet proto-plus jest to, że konwertuje wiadomości protobuf i dobrze znane typy na wbudowane typy Pythona w procesie zwanym porządkowaniem typów.

Przekształcanie następuje, gdy uzyskiwany jest dostęp do pola w instancji wiadomości proto-plus, a konkretnie gdy pole jest odczytywane lub ustawiane, na przykład w definicji protobuf:

syntax = "proto3";

message Dog {
  string name = 1;
}

Po przekonwertowaniu tej definicji na klasę proto-plus wygląda ona 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 w przypadku każdego innego obiektu Pythona:

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

Podczas odczytywania i ustawiania pola name wartość jest konwertowana z wbudowanego typu str Pythona na typ string, aby była zgodna ze środowiskiem wykonawczym protobuf.

Czas poświęcony na konwersję tych typów ma na tyle duży wpływ na wydajność, że należy zdecydować, czy używać wiadomości proto-plus czy protobuf, w zależności od potrzeb aplikacji.

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 komunikatami protobuf, dzięki czemu idealnie nadaje się do pisania łatwego w utrzymaniu i czytelnego kodu. Ponieważ udostępniają standardowe obiekty Pythona, są łatwiejsze w użyciu i zrozumieniu.
Przypadki użycia wiadomości Protobuf
Używaj buforów protokołu w przypadkach, gdy wydajność ma kluczowe znaczenie, zwłaszcza w aplikacjach, które muszą szybko przetwarzać duże raporty lub tworzyć żądania modyfikacji z dużą liczbą operacji, np. za pomocą BatchJobService lub OfflineUserDataJobService.

Dynamiczne przełączanie typów wiadomości

Po wybraniu odpowiedniego typu wiadomości dla aplikacji może się okazać, że w przypadku konkretnego przepływu pracy musisz użyć innego typu. W takim przypadku możesz dynamicznie przełączać się między tymi 2 typami, korzystając z narzędzi dostępnych w bibliotece klienta. Użyj tej samej klasy wiadomości Dog co wcześniej:

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 udokumentowany, a w poniższych sekcjach opisano najważniejsze różnice, które wpływają 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 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. Jeśli używasz wiadomości proto-plus, przekonwertuj je na wiadomości protobuf, aby użyć funkcji pomocniczej:

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

Typy wyliczeniowe udostępniane przez wiadomości proto-plus są instancjami wbudowanego typu enum w Pythonie, dlatego dziedziczą wiele przydatnych metod.

Pobieranie typu wyliczeniowego

Gdy używasz metody GoogleAdsClient.get_type do pobierania typów wyliczeniowych, 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 Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Aby ułatwić pobieranie typów wyliczeniowych, instancje GoogleAdsClient mają wygodny atrybut, który ma spójny interfejs niezależnie od używanego typu wiadomości:

val = client.enums.CampaignStatusEnum.PAUSED

Pobieranie wartości typu wyliczeniowego

Czasami przydatna jest znajomość wartości lub identyfikatora pola danego typu wyliczeniowego, na przykład PAUSED w 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
# 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"))

Pobieranie nazwy typu wyliczeniowego

Czasami przydaje się znajomość nazwy pola typu wyliczeniowego. Na przykład podczas odczytywania obiektów z interfejsu API możesz chcieć wiedzieć, któremu stanowi kampanii odpowiada liczba całkowita 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
print(status_enum.CampaignStatus.Name(campaign.status))

Pola powtarzane

Jak opisano w dokumentacji proto-plus, pola powtarzane są zwykle odpowiednikami list typowanych, co oznacza, że zachowują się prawie identycznie jak list.

Dołączanie wartości do powtarzanych pól skalarnych

Podczas dodawania wartości do powtarzających się pól typu skalarnego, np. 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 też wszystkie inne typowe metody list, na przykład 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 powtarzanych

Jeśli pole powtarzane nie jest typu skalarnego, zachowanie podczas dodawania do pól powtarzanych jest nieco inne:

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 powtarzanych

W przypadku pól powtarzanych skalarnych i nieskalarnych możesz przypisywać listy do pola 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 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 warto wiedzieć, czy instancja wiadomości zawiera jakieś informacje lub czy ma ustawione jakieś pola.

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

Treść wiadomości

W przypadku wiadomości proto-plus i protobuf użyj 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 typu wiadomości, której używasz. Skopiuj pustą wiadomość do odpowiedniego pola. Zapoznaj się z sekcją Kopia wiadomości oraz przewodnikiem Puste pola wiadomości. Poniższy przykład pokazuje, jak ustawić puste pole wiadomości:

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

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

Podczas korzystania z wiadomości proto-plus nazwy pól automatycznie pojawiają się z podkreśleniem na końcu, jeśli nazwa jest też słowem zarezerwowanym w Pythonie. Poniższy przykład pokazuje, jak pracować z instancją Asset:

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

Pełna lista zarezerwowanych nazw jest tworzona w module generatora gapic. Można też uzyskać do niego dostęp automatycznie.

Najpierw zainstaluj moduł:

python -m pip install gapic-generator

Następnie w skrypcie lub pętli REPL Pythona:

import gapic.utils

print(gapic.utils.reserved_names.RESERVED_NAMES)

Obecność pola

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

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

Interfejs klasy protobuf Message ma metodę HasField, która określa, czy podwiadomość, pole oneof lub pole skalarne optional w wiadomości zostało ustawione, nawet jeśli ustawiono wartość domyślną. (Wywołanie HasField w przypadku nieopcjonalnych pól skalarnych w proto3 powoduje błąd ValueError).

Metody wiadomości Protobuf

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

Narzędzie Issue Tracker

Jeśli masz pytania dotyczące tych zmian lub problemy z migracją do najnowszej wersji biblioteki, zgłoś problem w narzędziu Issue Tracker.