La 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 muestre mensajes proto-plus o mensajes protobuf. Para obtener detalles sobre cómo configurar este parámetro, consulta los documentos de configuración.
En esta sección, se describen las implicaciones de rendimiento que tiene elegir qué tipos de mensajes usar; por lo tanto, te recomendamos que leas y comprendas las opciones para tomar una decisión fundamentada. Sin embargo, si deseas actualizar a la versión 14.0.0
sin realizar cambios en el código, puedes configurar use_proto_plus
como True
para evitar cambios que se interrumpan en la interfaz.
Diferencias entre mensajes proto+ y protobuf
En la versión 10.0.0
, la biblioteca cliente de Python migró a una nueva canalización de generador de código que integró proto-plus como una forma de mejorar la ergonomía de la interfaz de mensajes protobuf haciendo que se comporten más como objetos nativos de Python. La desventaja de esta mejora es que proto-plus ingresa una sobrecarga de rendimiento.
Rendimiento de proto+
Uno de los beneficios principales de proto-plus es que convierte mensajes de protobuf y tipos conocidos en tipos nativos de Python a través de un proceso llamado ordenamiento de tipos.
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 se establece, por ejemplo, en una definición de protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Cuando esta definición se convierta en una clase proto-plus, se vería de la siguiente manera:
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 con 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 tipo nativo str
de Python a un tipo string
para 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
, determinamos que el tiempo dedicado a realizar estas conversiones de tipos tiene un impacto en el rendimiento lo suficientemente grande como para que es importante darles a los usuarios la opción de usar mensajes protobuf.
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 sostenible. 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 necesitan procesar informes grandes con rapidez o que compilan solicitudes de mutación con una gran cantidad de operaciones, por ejemplo, con
BatchJobService
oOfflineUserDataJobService
.
Tipos de mensajes que cambian de forma dinámica
Después de seleccionar el tipo de mensaje adecuado para tu app, es posible que debas usar el otro tipo para un flujo de trabajo específico. En este caso, es fácil cambiar entre los dos tipos de forma dinámica con 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 de la biblioteca cliente de Google Ads.
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 que proporciona api-core está diseñado para usar instancias de mensajes protobuf. Por lo tanto, cuando uses mensajes proto-plus, conviértelos en mensajes protobuf para usar 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)
Enumeradores
Las enumeraciones que exponen los mensajes proto-plus son instancias del tipo enum
nativo de Python y, por lo tanto, heredan 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 muestran son un poco 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 simplificar la recuperación de enumeraciones, hay un atributo de conveniencia en las instancias de GoogleAdsClient
que tiene una interfaz coherente, sin importar el tipo de mensaje que uses:
val = client.enums.CampaignStatusEnum.PAUSED
Recuperación de valores de enumeración
A veces, es útil conocer el valor o el ID de campo de una enumeración determinada, 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 lees objetos de la API, es posible que desees saber a qué estado de la campaña corresponde el parámetro 3
:
- 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 los documentos proto-plus, los campos repetidos, por lo general, son equivalentes a las listas escritas, lo que significa que se comportan casi de forma idéntica a list
.
Cómo adjuntar campos escalares repetidos
Cuando se agregan valores a campos de tipo escalar repetidos, por ejemplo, campos string
o int64
, la interfaz es la misma, sin importar el tipo de mensaje:
- 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 tipo escalar, el comportamiento cuando se agregan a 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 campo 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 si configuró 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, te recomendamos usar el método auxiliar copy_from
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 del tipo de mensaje que uses. Solo debes copiar un mensaje vacío en el campo en cuestión. Consulta la sección Copia de mensaje y la guía Campos de mensaje vacíos. El siguiente es un ejemplo de cómo configurar un campo de mensaje vacío:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
Nombres de campos que son palabras reservadas
Cuando usas 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. El siguiente es un ejemplo de cómo trabajar con una instancia Asset
:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
La lista completa de nombres reservados se construye en el módulo gapic generator. También se puede acceder a ella de manera 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 siempre es intuitivo saber si un campo se configuró 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")
La interfaz de la clase Message
de protobuf tiene un método HasField
que determina si se configuró el campo en un mensaje, incluso si se estableció en un valor predeterminado.
Métodos de mensajes de protobuf
La interfaz de mensajes protobuf incluye algunos métodos útiles que no forman parte de la interfaz proto-plus. Sin embargo, es fácil acceder a ellos convirtiendo un mensaje proto-plus en su equivalente de 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())
Herramienta de seguimiento de errores
Si tienes alguna pregunta sobre estos cambios o problemas para migrar a la versión 14.0.0
de la biblioteca, informa el problema en nuestra herramienta de seguimiento.