Wiadomości protokołu Protobuf

Wersja 14.0.0 biblioteki klienta Pythona 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 ustawianiu tego parametru znajdziesz w dokumentacji konfiguracji.

Ta sekcja opisuje wpływ wyboru typów komunikatów na wydajność, dlatego zalecamy zapoznanie się z dostępnymi opcjami, aby podjąć świadomą decyzję. Jeśli jednak chcesz uaktualnić go do wersji 14.0.0 bez wprowadzania zmian w kodzie, możesz ustawić parametr use_proto_plus na True, aby uniknąć zmian w interfejsie.

Wiadomości protoplus i protobuf

W wersji 10.0.0 biblioteka klienta w Pythonie została przeniesiona do nowego potoku generatora kodu, który zintegrował proto-plus w celu poprawy ergonomii interfejsu wiadomości protobuf przez zmianę ich działania w sposób podobny do natywnych obiektów Pythona. Kompromisem tego ulepszenia jest to, że proto-plus wprowadza wymagania dotyczące wydajności.

Wydajność Proto-plus

Jedną z głównych zalet proto-plusa jest to, że konwertuje wiadomości protobuf i dobrze znane typy na natywne typy Pythona przy użyciu protokołu typu marshall.

Organizowanie ma miejsce, gdy dostęp do pola uzyskuje się w instancji wiadomości proto-plus, zwłaszcza gdy pole jest odczytywane lub ustawione, na przykład w definicji protokołu:

syntax = "proto3";

message Dog {
  string name = 1;
}

Po przekonwertowaniu tej definicji na klasę proto-plus będzie ona 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 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 natywnego typu str w Pythonie na string, co zapewnia zgodność ze środowiskiem wykonawczym protobuf.

W analizie przeprowadzonej od momentu opublikowania wersji 10.0.0 stwierdziliśmy, że czas poświęcony na przeprowadzanie konwersji tego typu ma na tyle duży wpływ na skuteczność, że ważne jest zapewnienie użytkownikom możliwości korzystania z wiadomości protobuf.

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

Przypadki użycia wiadomości Proto-plus
Proto-plus ma szereg ergonomicznych ulepszeń w porównaniu z protobufami, dzięki czemu idealnie nadaje się do pisania łatwego w użyciu i czytelnego kodu. Ponieważ ujawniają one natywne obiekty Pythona, są łatwiejsze w użyciu i zrozumieniu.
Przypadki użycia wiadomości w protobuf
Używaj protokołów w przypadkach użycia związanych z wydajnością, zwłaszcza w aplikacjach, w których musisz szybko przetwarzać duże raporty lub które tworzą żądania mutacji obejmujące dużą liczbę operacji, np. w BatchJobService lub OfflineUserDataJobService.

Dynamicznie zmieniające się typy wiadomości

Po wybraniu odpowiedniego typu wiadomości dla swojej aplikacji może się okazać, że musisz użyć innego typu w określonym przepływie pracy. W tym przypadku można łatwo przełączać się między tymi dwoma typami funkcji, korzystając z narzędzi dostępnych w bibliotece klienta. Użycie tej samej klasy wiadomości Dog z podanej wyżej listy:

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 komunikatów w protobuf

Interfejs proto-plus jest szczegółowo opisany, ale tutaj omówimy kilka najważniejszych różnic, 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 w protokole Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Serializacja JSON

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

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

Maski pól

Metoda pomocnicza maski pól udostępniana przez api-core jest przeznaczona do korzystania z instancji wiadomości protobuf. Jeśli więc używasz wiadomości proto-plus, przekonwertuj je na wiadomości protobuf, aby użyć wiadomości pomocniczej:

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

Wyliczenia widoczne dla wiadomości proto-plus to instancje natywnego typu enum Pythona, więc dziedziczą one szereg udogodnień.

Pobieranie typu wyliczenia

W przypadku pobierania wyliczeń za pomocą metody GoogleAdsClient.get_type zwracane wiadomości różnią się nieco 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 w protokole Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Aby uprościć pobieranie wyliczeń, wprowadziliśmy atrybut udogodnień w instancjach GoogleAdsClient, które mają spójny interfejs niezależnie od używanego typu wiadomości:

val = client.enums.CampaignStatusEnum.PAUSED

Pobranie wartości wyliczenia

Czasami warto znać wartość lub identyfikator pola danej wyliczenia. Na przykład PAUSED w CampaignStatusEnum odpowiada wartości 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 w protokole 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))

Pobranie nazwy w Enum

Czasami warto znać nazwę pola wyliczenia. Na przykład podczas odczytywania obiektów z interfejsu API możesz chcieć się dowiedzieć, któremu stanowi kampanii odpowiada intencja 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 w protokole 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 protokołu, pola powtarzane są zasadniczo równoważne z listami wpisanymi, co oznacza, że działają prawie identycznie jak pola list.

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

W przypadku dodawania wartości do powtarzających się pól typu skalarnego, np. pól string lub int64, interfejs jest taki sam niezależnie od typu komunikatu:

Wiadomości Proto-plus
ad.final_urls.append("https://www.example.com")
Wiadomości w protokole 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 w protokole 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 skalarnym, działanie podczas dodawania ich do powtarzanych pól jest nieco inne:

Wiadomości Proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Wiadomości w protokole 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 skalarnych, jak i nieskalarnych polach powtarzanych 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 w protokole 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 sprawdzić, czy instancja wiadomości zawiera jakiekolwiek informacje lub czy ma ustawione któreś z jej pól.

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 w protokole Protobuf
is_empty = campaign.ByteSize() == 0

Kopiowanie wiadomości

W przypadku wiadomości proto-plus i protobufów zalecamy użycie metody pomocniczej copy_from w interfejsie 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 skopiować pustą wiadomość w odpowiednie pole. Zapoznaj się z sekcją Tekst wiadomości i przewodnikiem Puste pola wiadomości. Oto przykład ustawiania pustego pola wiadomości:

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

Nazwy pól, które są zarezerwowanymi słowami

Gdy używasz wiadomości proto-plus, nazwy pól są automatycznie wyświetlane ze znakiem na końcu, jeśli jest ona również 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 zarezerwowanych nazw jest tworzona w module generatora GApic. Można też uzyskać do nich dostęp automatycznie.

Najpierw zainstaluj moduł:

python -m pip install gapic-generator

Następnie w języku REPL lub skrypcie w Pythonie:

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

Obecność pól

Pola w instancjach wiadomości w protokole protobuf mają wartości domyślne, dlatego nie zawsze można sprawdzić, czy pole zostało ustawione.

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

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

Metody wysyłania wiadomości w protobufach

Interfejs wiadomości w protokole protobuf zawiera pewne wygodne metody, które nie są częścią interfejsu protoplus. Aby uzyskać do nich dostęp, wystarczy skonwertować wiadomość proto-plus na jej odpowiednik w protokole 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 masz problemy z przejściem na wersję 14.0.0 biblioteki, zgłoś problem w naszym trackerze.