С помощью параметра конфигурации use_proto_plus
вы можете указать, хотите ли вы, чтобы библиотека возвращала сообщения proto-plus или сообщения protobuf . Подробную информацию о том, как установить этот параметр, смотрите в документации по конфигурации .
В этом разделе описываются последствия выбора типа сообщений для производительности, поэтому мы рекомендуем вам прочитать и понять варианты, чтобы принять обоснованное решение.
Сообщения Proto-plus и protobuf
Конвейер генератора кода интегрирует 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.
Основываясь на нашем анализе производительности, мы определили, что время, затрачиваемое на эти преобразования типов, оказывает достаточно большое влияние на производительность, поэтому пользователи должны решить, исходя из своих потребностей, использовать или нет сообщения 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 Рекламы.
Сериализация байтов
- Прото-плюс сообщения
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Протобуф-сообщения
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Сериализация JSON
- Прото-плюс сообщения
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Протобуф-сообщения
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)
- Протобуф-сообщения
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Перечисления
Перечисления, предоставляемые сообщениями proto-plus, являются экземплярами собственного типа enum
Python и, следовательно, наследуют ряд удобных методов.
Получение типа перечисления
При использовании метода GoogleAdsClient.get_type
для получения перечислений возвращаемые сообщения немного различаются в зависимости от того, используете ли вы сообщения proto-plus или protobuf. Например:
- Прото-плюс сообщения
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Протобуф-сообщения
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)
- Протобуф-сообщения
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)
- Протобуф-сообщения
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")
- Протобуф-сообщения
ad.final_urls.append("https://www.example.com")
Сюда также входят все другие распространенные методы list
, например, extend
:
- Прото-плюс сообщения
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Протобуф-сообщения
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)
- Протобуф-сообщения
# 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 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
- Протобуф-сообщения
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
Полный список зарезервированных имен формируется в модуле генератора пробелов . Доступ к нему можно получить и программно.
Сначала установите модуль:
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
- Протобуф-сообщения
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
Интерфейс класса protobuf Message
имеет метод 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())
Трекер проблем
Если у вас есть какие-либо вопросы по поводу этих изменений или проблем при переходе на последнюю версию библиотеки, сообщите о проблеме на нашем трекере.
, С помощью параметра конфигурации use_proto_plus
вы можете указать, хотите ли вы, чтобы библиотека возвращала сообщения proto-plus или сообщения protobuf . Подробности о том, как установить этот параметр, см. в документации по конфигурации .
В этом разделе описываются последствия выбора типа сообщений для производительности, поэтому мы рекомендуем вам прочитать и понять варианты, чтобы принять обоснованное решение.
Сообщения Proto-plus и protobuf
Конвейер генератора кода интегрирует 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.
Основываясь на нашем анализе производительности, мы определили, что время, затрачиваемое на эти преобразования типов, оказывает достаточно большое влияние на производительность, поэтому пользователи должны решить, исходя из своих потребностей, использовать или нет сообщения 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 Рекламы.
Сериализация байтов
- Прото-плюс сообщения
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Протобуф-сообщения
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Сериализация JSON
- Прото-плюс сообщения
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Протобуф-сообщения
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)
- Протобуф-сообщения
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Перечисления
Перечисления, предоставляемые сообщениями proto-plus, являются экземплярами собственного типа enum
Python и, следовательно, наследуют ряд удобных методов.
Получение типа перечисления
При использовании метода GoogleAdsClient.get_type
для получения перечислений возвращаемые сообщения немного различаются в зависимости от того, используете ли вы сообщения proto-plus или protobuf. Например:
- Прото-плюс сообщения
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Протобуф-сообщения
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)
- Протобуф-сообщения
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)
- Протобуф-сообщения
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")
- Протобуф-сообщения
ad.final_urls.append("https://www.example.com")
Сюда также входят все другие распространенные методы list
, например, extend
:
- Прото-плюс сообщения
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Протобуф-сообщения
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)
- Протобуф-сообщения
# 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 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
- Протобуф-сообщения
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
Полный список зарезервированных имен формируется в модуле генератора пробелов . Доступ к нему можно получить и программно.
Сначала установите модуль:
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
- Протобуф-сообщения
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
Интерфейс класса protobuf Message
имеет метод 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())
Трекер проблем
Если у вас есть какие-либо вопросы по поводу этих изменений или проблем при переходе на последнюю версию библиотеки, сообщите о проблеме на нашем трекере.