Wiadomości protobuf

Wersja 14.0.0 biblioteki klienta w języku Python wprowadza nowy wymagany parametr konfiguracji o nazwie use_proto_plus, który określa, 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.

W tej sekcji opisano wpływ wiadomości na wydajność, dlatego zalecamy zapoznanie się z tymi opcjami i podjęcie przemyślanej decyzji. Jeśli jednak chcesz uaktualnić pakiet do wersji 14.0.0 bez wprowadzania zmian w kodzie, możesz ustawić use_proto_plus na True, aby uniknąć uszkodzenia interfejsu.

Komunikaty protokołu plus i protobuf

W wersji 10.0.0 biblioteka klienta w Pythonie została przeniesiona do nowego potoku generatora kodu, który zintegrował proto-plus, aby poprawić ergonomię interfejsu wiadomości protobuf. Kompromis ten polega na tym, że rozwiązania proto-plus zwiększają nakład pracy.

Wydajność proto-plus

Jedną z głównych zalet protokołu proto-plus jest przekształcanie wiadomości protobuf i dobrze znanych typów na natywne typy Pythona w ramach procesu masażu typu.

Halhall występuje wtedy, gdy pole jest używane w instancji komunikatu protoplus, zwłaszcza gdy pole jest odczytywane lub ustawiane, na przykład w definicji protobuf:

syntax = "proto3";

message Dog {
  string name = 1;
}

Gdy ta definicja zostanie przekonwertowana na 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 każdy inny obiekt w Pythonie:

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

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

W analizie przeprowadzonej od momentu opublikowania wersji 10.0.0 stwierdziliśmy, że czas poświęcony na takie konwersje jest wystarczająco duży, aby zapewnić użytkownikom możliwość korzystania z wiadomości protobuf.

Przypadki użycia wiadomości protoplus i protobuf

Przypadki użycia wiadomości proto-plus
Protoplus oferuje szereg ergonomicznych ulepszeń w porównaniu z wiadomościami protobuf, dzięki czemu idealnie nadają się do pisania czytelnego kodu. Udostępniają natywne obiekty w Pythonie, więc są łatwiejsze w obsłudze i zrozumieniu.
Przypadki użycia wiadomości Protobuf
Korzystaj z protokołów w przypadkach użycia wymagających bardzo dużej wydajności, zwłaszcza w aplikacjach, które muszą szybko przetwarzać duże raporty lub gdy żądania mutują dużą liczbę operacji, na przykład BatchJobService lub OfflineUserDataJobService.

Dynamiczne zmienianie typów wiadomości

Po wybraniu odpowiedniego typu wiadomości dla swojej aplikacji może się okazać, że musisz użyć innego typu dla danego przepływu pracy. W takim przypadku można łatwo przełączać się między tymi 2 typami za pomocą narzędzi dostępnych w bibliotece klienta. Przy użyciu tej samej klasy wiadomości w 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)

Różnice w interfejsie protokołu Protobuf

Interfejs proto-plus jest omówiony szczegółowo, ale tutaj omówimy najważniejsze różnice, które mają wpływ na typowe przypadki użycia biblioteki klienta Google Ads.

serializacja bajtów,

Wiadomości proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Wiadomości Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Seria serializacji JSON

Wiadomości proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Wiadomości Protobuf
from google.protobuf.json_format import MessageToJson, Parse

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

Maski pól

Metoda pomocnicza pola maskowana przez api-core jest przeznaczona do używania instancji protobuf. Jeśli korzystasz z wiadomości protoplus, przekonwertuj je na wiadomości protobuf, aby używać w tym pomocniku:

Wiadomości 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)
Wiadomości 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

Wykazywane są wiadomości proto-plus, które są natywnym typem języka enum w Pythonie i w związku z tym dziedziczą wiele metod wygodnych.

Pobieranie typu Enum

Przy pobieraniu metody wyliczeniowej GoogleAdsClient.get_type metoda zwracanych wiadomości wygląda nieco inaczej w zależności od tego, czy używasz wiadomości proto-plus, czy protobuf. Na przykład:

Wiadomości proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Wiadomości Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Aby uprościć pobieranie wyliczeń, udostępniliśmy atrybut wygodnej instancji GoogleAdsClient, który ma spójny interfejs niezależnie od używanego typu wiadomości:

val = client.enums.CampaignStatusEnum.PAUSED

Pobieranie wartości num

Czasami przydatna jest znajomość wartości (identyfikatora pola) określonego wyliczenia, na przykład PAUSED w CampaignStatusEnum odpowiada 3:

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

Czasami dobrze jest znać nazwę pola wyliczeniowego. Podczas odczytywania obiektów z interfejsu API możesz na przykład sprawdzić, jaki stan kampanii odpowiada 3:

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

Zgodnie z dokumentacją proto-plus pola powtarzane są zwykle równoważne z listami wpisanymi, co oznacza, że działają prawie tak samo jak list.

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

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

Wiadomości proto-plus
ad.final_urls.append("https://www.example.com")
Wiadomości Protobuf
ad.final_urls.append("https://www.example.com")

Obejmuje to też wszystkie inne popularne metody list, np. extend:

Wiadomości proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Wiadomości 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 typem skalowania, działanie podczas dodawania ich do pól powtarzanych może wyglądać trochę inaczej:

Wiadomości proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Wiadomości 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

Zarówno w przypadku pól skalarnych, jak i nieskalowanych, możesz przypisywać listy do pola na różne sposoby:

Wiadomości proto-plus
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Wiadomości 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 dobrze jest sprawdzić, czy instancja wiadomości zawiera jakiekolwiek informacje lub czy zawiera jakieś pola.

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

Treść wiadomości

W przypadku wiadomości protoplus i protobuf zalecamy użycie metody pomocniczej copy_from na stronie 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. Zobacz sekcję Tekst wiadomości oraz przewodnik po pustych polach 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ą zarezerwowanymi słowami

W przypadku wiadomości protoplus nazwy pól są automatycznie wyświetlane z podkreśleniem, jeśli są również zarezerwowanymi słowami w Pythonie. Oto przykład pracy z instancją Asset:

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

Pełną listę zarezerwowanych nazw tworzy się w module generatora gapiców. Dostęp do nich może być też zautomatyzowany.

Najpierw zainstaluj moduł:

python -m pip install gapic-generator

Następnie, korzystając z Pythona REPL lub skryptu:

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

Obecność pola

Pola w instancjach wiadomości protobuf mają wartości domyślne, dlatego nie zawsze jest intuicyjny sposób określania, czy pole zostało ustawione.

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

Interfejs klasy protobuf Message używa metody HasField, która określa, czy pole w wiadomości zostało ustawione, nawet jeśli jest to wartość domyślna.

Metody wysyłania wiadomości protobuf

Interfejs wiadomości protobuf obejmuje niektóre metody wygodne, które nie są częścią interfejsu protoplus. Można go jednak łatwo uzyskać, konwertując komunikat protobuf na jego odpowiednik w 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 problemów z przejściem na 14.0.0 w bibliotece, zgłoś problem w naszym narzędziu do śledzenia błędów.