С помощью параметра конфигурации use_proto_plus можно указать, какие сообщения должна возвращать библиотека: proto-plus или protobuf. Подробнее о том, как задать этот параметр…
В этом разделе описано, как каждый из вариантов влияет на производительность, чтобы вы могли выбрать оптимальный подход для своего приложения.
Сообщения Proto-plus и Protocol Buffers
Конвейер генератора кода интегрирует proto-plus, чтобы улучшить эргономику интерфейса сообщений protobuf, сделав их более похожими на стандартные объекты Python. Однако это означает, что использование proto-plus приводит к снижению производительности.
Эффективность прототипов
Одно из основных преимуществ proto-plus заключается в том, что он преобразует сообщения protobuf и известные типы во встроенные типы Python с помощью процесса, называемого маршалингом типов.
Маршалинг происходит, когда к полю обращаются в экземпляре сообщения proto-plus, а именно когда поле считывается или задается, например в определении protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
При преобразовании этого определения в класс proto-plus оно будет выглядеть следующим образом:
import proto
class Dog(proto.Message):
name = proto.Field(proto.STRING, number=1)
Затем можно инициализировать класс Dog и получить доступ к его полю name, как и к любому другому объекту Python:
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
При чтении и задании значения поля name оно преобразуется из встроенного типа Python str в тип string, чтобы оно было совместимо с исполняемой средой protobuf.
Время, затраченное на преобразование типов, оказывает достаточно большое влияние на производительность, поэтому вам следует решить, исходя из потребностей вашего приложения, использовать ли сообщения proto-plus или protobuf.
Примеры использования proto-plus и сообщений protobuf
- Примеры использования сообщений Proto-Plus
- Proto-plus предлагает ряд эргономичных улучшений по сравнению с сообщениями protobuf, поэтому они идеально подходят для написания поддерживаемого и читаемого кода. Поскольку они предоставляют доступ к стандартным объектам Python, их проще использовать и понимать.
- Примеры использования сообщений Protobuf
- Используйте protobuf для задач, требующих высокой производительности, особенно в приложениях, которым нужно быстро обрабатывать большие отчеты или создавать запросы на изменение с большим количеством операций, например с
BatchJobServiceилиOfflineUserDataJobService.
Динамическое переключение типов сообщений
После того как вы выберете подходящий тип сообщения для своего приложения, вы можете обнаружить, что для определенного рабочего процесса вам нужен другой тип. В этом случае вы можете динамически переключаться между двумя типами, используя утилиты, предлагаемые клиентской библиотекой. Используя тот же класс сообщений 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)
Различия в интерфейсе сообщений Protobuf
Интерфейс proto-plus подробно описан в документации. В следующих разделах рассказывается об основных различиях, которые влияют на распространенные варианты использования клиентской библиотеки Google Рекламы.
Сериализация байтов
- Сообщения Proto-plus
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Сообщения Protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Сериализация JSON
- Сообщения Proto-plus
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Сообщения Protobuf
from google.protobuf.json_format import MessageToJson, Parse serialized = MessageToJson(campaign) deserialized = Parse(serialized, campaign)
Маски полей
Вспомогательный метод маски поля, предоставляемый api-core, предназначен для использования экземпляров сообщений protobuf. Если вы используете сообщения proto-plus, преобразуйте их в сообщения protobuf, чтобы использовать помощника:
- Сообщения 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)
- Сообщения Protobuf
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Перечисления
Перечисления, представленные в сообщениях proto-plus, являются экземплярами встроенного типа Python enum и поэтому наследуют ряд удобных методов.
Получение типа перечисления
При использовании метода GoogleAdsClient.get_type для получения перечислений возвращаемые сообщения немного отличаются в зависимости от того, используете ли вы сообщения proto-plus или protobuf. Пример:
- Сообщения Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Сообщения Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Чтобы упростить получение перечислений, в экземплярах GoogleAdsClient есть удобный атрибут с единообразным интерфейсом независимо от того, какой тип сообщения вы используете:
val = client.enums.CampaignStatusEnum.PAUSED
Получение значения перечисления
Иногда полезно знать значение или идентификатор поля определенного перечисления. Например, PAUSED в CampaignStatusEnum соответствует 3:
- Сообщения Proto-plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the value of campaign status print(campaign.status.value)
- Сообщения 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"))
Получение названия перечисления
Иногда полезно знать название поля перечисления. Например, при чтении объектов из API вам может понадобиться узнать, какому статусу кампании соответствует целое число 3:
- Сообщения Proto-plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the name of campaign status print(campaign.status.name)
- Сообщения 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))
Повторяющиеся поля
Как описано в документации по proto-plus, повторяющиеся поля обычно эквивалентны типизированным спискам, а значит, ведут себя почти так же, как list.
Добавление значений в повторяющиеся скалярные поля
При добавлении значений в повторяющиеся поля скалярного типа, например в поля string или int64, интерфейс будет одинаковым независимо от типа сообщения:
- Сообщения Proto-plus
ad.final_urls.append("https://www.example.com")
- Сообщения Protobuf
ad.final_urls.append("https://www.example.com")
Это также относится ко всем другим распространенным методам list, например extend:
- Сообщения Proto-plus
ad.final_urls.extend( ["https://www.example.com", "https://www.example.com/2"] )
- Сообщения Protobuf
ad.final_urls.extend( ["https://www.example.com", "https://www.example.com/2"] )
Добавление типов сообщений в повторяющиеся поля
Если повторяющееся поле не является скалярным типом, поведение при добавлении в него элементов будет немного отличаться:
- Сообщения Proto-plus
frequency_cap = client.get_type("FrequencyCapEntry") frequency_cap.cap = 100 campaign.frequency_caps.append(frequency_cap)
- Сообщения Protobuf
# The add method initializes a message and adds it to the repeated field frequency_cap = campaign.frequency_caps.add() frequency_cap.cap = 100
Как назначить повторяющиеся поля
Для скалярных и нескалярных повторяющихся полей можно назначать списки разными способами:
- Сообщения Proto-plus
# In proto-plus it's possible to use assignment. urls = ["https://www.example.com"] ad.final_urls = urls
- Сообщения 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
Пустые письма
Иногда полезно знать, содержит ли экземпляр сообщения какую-либо информацию или заданы ли какие-либо его поля.
- Сообщения Proto-plus
# When using proto-plus messages you can check the message for truthiness. is_empty = not bool(campaign)
- Сообщения Protobuf
is_empty = campaign.ByteSize() == 0
Копия сообщения
Для сообщений proto-plus и protobuf используйте вспомогательный метод copy_from в GoogleAdsClient:
client.copy_from(campaign, other_campaign)
Пустые поля сообщения
Процесс настройки пустых полей сообщений одинаков для всех типов сообщений. Вы копируете пустое сообщение в нужное поле. Ознакомьтесь с разделом Копия письма и руководством Пустые поля письма. В примере ниже показано, как задать пустое поле сообщения:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
Названия полей, которые являются зарезервированными словами
При использовании сообщений proto-plus названия полей автоматически дополняются символом подчеркивания в конце, если название также является зарезервированным словом в Python. В следующем примере показано, как работать с экземпляром Asset:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
Полный список зарезервированных имен создается в модуле генератора gapic. К нему также можно получить программный доступ.
Сначала установите модуль:
python -m pip install gapic-generator
Затем в REPL или скрипте Python:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Наличие полей
Поскольку поля в экземплярах сообщений protobuf имеют значения по умолчанию, не всегда понятно, задано ли поле.
- Сообщения Proto-plus
# Use the "in" operator. has_field = "name" in campaign
- Сообщения Protobuf
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
У интерфейса класса protobuf Message есть метод HasField, который определяет, задано ли в сообщении вложенное сообщение, поле oneof или скалярное поле optional, даже если для него установлено значение по умолчанию.
(Вызов HasField для необязательных скалярных полей в proto3 вызывает ошибку ValueError.)
Методы сообщений Protobuf
Интерфейс сообщений protobuf включает некоторые удобные методы, которые не входят в интерфейс proto-plus. Однако вы можете получить к ним доступ, преобразовав сообщение proto-plus в его аналог 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()
Система отслеживания ошибок
Если у вас возникнут вопросы об этих изменениях или проблемы с переходом на последнюю версию библиотеки, сообщите о них в системе отслеживания ошибок.