Mensajes de protobuf

Versión 14.0.0 de la biblioteca cliente de Python presenta un nuevo parámetro de configuración obligatorio llamado use_proto_plus, que especifica si deseas que la biblioteca devuelva mensajes proto-plus o mensajes protobuf. Para obtener detalles para configurar este parámetro, consulta los documentos de configuración.

En esta sección, se describen las implicaciones de rendimiento que tiene elegir los tipos de mensajes usar, por lo tanto, te recomendamos que leas y comprendas las opciones para tomar una decisión informada. Sin embargo, si quieres actualizar a la versión 14.0.0 sin hacer cambios en el código, puedes configurar use_proto_plus a True para evitar cambios rotundos en la interfaz.

Diferencias entre mensajes proto+ y protobuf

En la versión 10.0.0, la biblioteca cliente de Python migró a un nuevo generador de código canalización que integró proto-plus como una forma de mejorar la ergonomía de la interfaz de mensajes protobuf, ya que hace que se comporten más como objetos nativos de Python. La compensación de esta mejora es que proto-plus presenta una sobrecarga de rendimiento.

Rendimiento de proto+

Uno de los principales beneficios de proto-plus es que convierte protobuf mensajes y los tipos bien conocidos para tipos nativos de Python a través de un proceso llamado type, el ordenamiento.

El ordenamiento se produce cuando se accede a un campo en una instancia de mensaje proto-plus. específicamente, cuando un campo se lee o establece, por ejemplo, en un protobuf definición:

syntax = "proto3";

message Dog {
  string name = 1;
}

Cuando esta definición se convierta en una clase proto-plus, se vería algo así. así:

import proto

class Dog(proto.Message):
    name = proto.Field(proto.STRING, number=1)

Luego, puedes inicializar la clase Dog y acceder a su campo name como lo harías. cualquier otro objeto de Python:

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

Cuando se lee y se configura el campo name, el valor se convierte de un nativo str de Python a un tipo string, de modo que que el valor sea compatible con el entorno de ejecución de protobuf.

En el análisis que realizamos desde el lanzamiento de la versión 10.0.0, determinó que el tiempo dedicado a generar este tipo de conversiones corresponde a un impacto en el rendimiento, es importante darles a los usuarios la opción de usar protobuf mensajes nuevos.

Casos de uso para mensajes proto-plus y protobuf

Casos de uso de proto-plus de mensajes
Proto-plus ofrece varias mejoras ergonómicas en comparación con los mensajes protobuf, por lo que son ideales para escribir código legible y mantenible. Dado que exponen objetos nativos de Python, son más fáciles de usar y comprender.
Casos de uso de mensajes de protobuf
Usa protobufs para casos de uso sensibles al rendimiento, específicamente en apps que necesiten procesar informes grandes rápidamente o que compilen solicitudes de mutación con una gran cantidad de operaciones, por ejemplo, con BatchJobService o OfflineUserDataJobService

Tipos de mensajes que cambian de forma dinámica

Después de seleccionar el tipo de mensaje adecuado para tu app, es posible que encuentres lo siguiente: que necesitas usar el otro tipo para un flujo de trabajo específico. En este caso, es puede cambiar de forma dinámica entre los dos tipos mediante las utilidades que ofrece la biblioteca cliente. Usa la misma clase de mensaje Dog anterior:

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)

Diferencias en la interfaz de mensajes de protobuf

La interfaz proto-plus está documentada en detalle, pero aquí destacaremos algunas diferencias clave que afectan los casos de uso comunes para el cliente de Google Ads biblioteca.

Serialización de bytes

Mensajes proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Mensajes de protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Serialización JSON

Mensajes proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Mensajes de protobuf
from google.protobuf.json_format import MessageToJson, Parse

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

Máscaras de campo

El método auxiliar de máscara de campo proporcionado por api-core está diseñado para usar protobuf. las instancias de mensajes nuevos. Por lo tanto, cuando uses mensajes proto-plus, conviértelos a protobuf. para utilizar el asistente:

Mensajes 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)
Mensajes de protobuf
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
mask = field_mask(None, campaign)

Enumeraciones

Las enumeraciones expuestas por mensajes proto-plus son instancias del lenguaje enum y, por lo tanto, heredarán varios métodos de conveniencia.

Recuperación de tipos de enumeraciones

Cuando usas el método GoogleAdsClient.get_type para recuperar enumeraciones, los mensajes que se devuelven son algo diferentes en función de si usas mensajes proto-plus o protobuf. Por ejemplo:

Mensajes proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Mensajes de protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Para facilitar la recuperación de enumeraciones, hay un atributo de conveniencia en Instancias GoogleAdsClient que tienen una interfaz coherente, sin importar la tipo de mensaje que utilizas:

val = client.enums.CampaignStatusEnum.PAUSED

Recuperación de valores de enumeración

A veces, es útil saber el valor, o ID de campo, de una enumeración determinada, por Por ejemplo, PAUSED en CampaignStatusEnum corresponde a 3:

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

Recuperación de nombres de enumeraciones

A veces, es útil saber el nombre de un campo enum. Por ejemplo, cuando leer objetos de la API, es posible que desees saber en qué estado de campaña int 3 corresponde a:

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

Campos repetidos

Como se describe en el módulo proto-plus documentos, los campos repetidos son generalmente equivalentes a las listas escritas, lo que significa que se comportan casi de forma idéntica a una list.

Cómo adjuntar campos escalares repetidos

Cuando se agregan valores a textos escalares repetidos type, por ejemplo, string o int64, la interfaz es la misma independientemente del mensaje Tipo:

Mensajes proto-plus
ad.final_urls.append("https://www.example.com")
Mensajes de protobuf
ad.final_urls.append("https://www.example.com")

Esto también incluye todos los demás métodos list comunes, por ejemplo, extend:

Mensajes proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Mensajes de protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

Adjunta tipos de mensajes a campos repetidos

Si el campo repetido no es un escalar del tipo de archivo, el comportamiento al momento de agregarlos los campos repetidos es un poco diferente:

Mensajes proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Mensajes de protobuf
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

Asigna campos repetidos

Para campos repetidos escalares y no escalares, puedes asignar listas al de diferentes maneras:

Mensajes proto-plus
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Mensajes de 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

Mensajes vacíos

A veces, es útil saber si una instancia de mensaje contiene información o que tenga configurado alguno de sus campos.

Mensajes proto-plus
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
Mensajes de protobuf
is_empty = campaign.ByteSize() == 0

Texto del mensaje

Para los mensajes proto-plus y protobuf, recomendamos usar copy_from. método auxiliar en GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Campos de mensaje vacíos

El proceso para configurar campos de mensaje vacíos es el mismo, independientemente de la el tipo de mensaje que usas. Solo tienes que copiar un mensaje vacío en el campo en cuestión. Consulta la sección Copia de mensaje, así como la sección Mensaje vacío Campos. Aquí hay un ejemplo de cómo Para configurar un campo de mensaje vacío, sigue estos pasos:

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

Nombres de campos que son palabras reservadas

Cuando se usan mensajes proto-plus, los nombres de los campos aparecen automáticamente con un guion bajo final si el nombre también es una palabra reservada en Python. Este es un Ejemplo de trabajo con una instancia Asset:

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

En la lista completa de anuncios nombres se construye en el gapic generator. Sí, es posible y a los que se puede acceder de forma programática.

Primero, instala el módulo:

python -m pip install gapic-generator

Luego, haz lo siguiente en una REPL o secuencia de comandos de Python:

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

Presencia en el campo

Debido a que los campos en las instancias de mensajes protobuf tienen valores predeterminados, no es necesario siempre es intuitivo para saber si un campo se ha configurado o no.

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

El protobuf Message de clase tiene un método HasField que determina si el campo en una mensaje, aunque se haya establecido en un valor predeterminado.

Métodos de mensajes de protobuf

La interfaz de mensajes protobuf incluye algunos métodos útiles que no son parte de la interfaz proto-plus; Sin embargo, es fácil acceder a ellos y convertir un mensaje proto-plus en su contraparte 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())

Seguimiento de problemas

Si tienes preguntas sobre estos cambios o problemas para migrar a versión 14.0.0 de la biblioteca, presenta una problema en nuestra de Google.