Параметр конфигурации use_proto_plus
позволяет указать, должна ли библиотека возвращать сообщения proto-plus или protobuf . Подробнее о настройке этого параметра см. в документации по конфигурации .
В этом разделе описываются последствия выбора типов сообщений для производительности, поэтому мы рекомендуем вам прочитать и понять варианты, чтобы принять обоснованное решение.
Сообщения Proto-plus и Protobuf
Конвейер генератора кода интегрирует Proto-Plus для улучшения эргономики интерфейса сообщений Protobuf, делая их более похожими на нативные объекты Python. Однако это означает, что использование Proto-Plus приводит к снижению производительности.
Производительность 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.
На основе анализа производительности мы определили, что время, затрачиваемое на эти преобразования типов, оказывает достаточно большое влияние на производительность, поэтому пользователи должны решить, использовать ли сообщения protobuf на основе своих потребностей.
Варианты использования сообщений proto-plus и protobuf
- Варианты использования сообщений Proto-plus
- Proto-plus предлагает ряд эргономичных улучшений по сравнению с сообщениями protobuf, поэтому они идеально подходят для написания удобного и читаемого кода. Поскольку они предоставляют доступ к собственным объектам Python, их проще использовать и понимать.
- Варианты использования сообщений Protobuf
- Используйте protobufs в случаях, когда производительность важна, особенно в приложениях, которым необходимо быстро обрабатывать большие отчеты или которые создают запросы на изменение с большим количеством операций, например, с помощью
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 Ads.
Сериализация байтов
- Прото-плюс сообщения
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Сообщения Protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
JSON-сериализация
- Прото-плюс сообщения
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, чтобы использовать этот вспомогательный метод:
- Прото-плюс сообщения
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, являются экземплярами собственного типа enum
Python и, следовательно, наследуют ряд удобных методов.
Извлечение типа Enum
При использовании метода GoogleAdsClient.get_type
для получения перечислений возвращаемые сообщения немного различаются в зависимости от того, используете ли вы сообщения proto-plus или protobuf. Например:
- Прото-плюс сообщения
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Сообщения Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Чтобы упростить извлечение перечислений, в экземплярах GoogleAdsClient
предусмотрен удобный атрибут, имеющий единообразный интерфейс независимо от того, какой тип сообщения вы используете:
val = client.enums.CampaignStatusEnum.PAUSED
Извлечение значения перечисления
Иногда полезно знать значение или идентификатор поля данного перечисления, например, PAUSED
в CampaignStatusEnum
соответствует 3
:
- Прото-плюс сообщения
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 # To read the value of campaign status print(status_enum.CampaignStatus.Value(campaign.status))
Получение имени перечисления
Иногда полезно знать имя поля перечисления. Например, при чтении объектов из API может потребоваться узнать, какому статусу кампании соответствует значение int 3
:
- Прото-плюс сообщения
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 status_enum.CampaignStatus.Name(campaign.status)
Повторяющиеся поля
Как описано в документации proto-plus , повторяющиеся поля, как правило, эквивалентны типизированным спискам, что означает, что они ведут себя почти идентично list
.
Добавлять значения к повторяющимся скалярным полям
При добавлении значений в повторяющиеся поля скалярного типа , например, поля string
или int64
, интерфейс остается одинаковым независимо от типа сообщения:
- Прото-плюс сообщения
ad.final_urls.append("https://www.example.com")
- Сообщения Protobuf
ad.final_urls.append("https://www.example.com")
Это также включает в себя все другие общие методы list
, например extend
:
- Прото-плюс сообщения
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"])
Добавлять типы сообщений к повторяющимся полям
Если повторяющееся поле не является скалярным типом , поведение при добавлении их к повторяющимся полям немного отличается:
- Прото-плюс сообщения
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
Назначить повторяющиеся поля
Как для скалярных, так и для нескалярных повторяющихся полей вы можете назначать списки полю различными способами:
- Прото-плюс сообщения
# 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
Пустые сообщения
Иногда полезно узнать, содержит ли экземпляр сообщения какую-либо информацию или установлены ли какие-либо его поля.
- Прото-плюс сообщения
# When using proto-plus messages you can simply check the message for # truthiness. is_empty = bool(campaign) is_empty = not 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 имеют значения по умолчанию, не всегда интуитивно понятно, было ли задано поле или нет.
- Прото-плюс сообщения
# 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")
Интерфейс класса Message
protobuf имеет метод HasField
, который определяет, было ли задано поле в сообщении, даже если для него было установлено значение по умолчанию.
Методы сообщений Protobuf
Интерфейс сообщений protobuf включает в себя некоторые удобные методы, которые не являются частью интерфейса proto-plus; однако к ним легко получить доступ, преобразовав сообщение proto-plus в его аналог 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())
Отслеживание проблем
Если у вас возникли вопросы по поводу этих изменений или проблемы с переходом на последнюю версию библиотеки, сообщите об этом в нашем трекере.