Con el parámetro de configuración use_proto_plus, puedes especificar si deseas que la biblioteca devuelva mensajes de proto-plus o mensajes de 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 de cada opción para que puedas elegir el mejor enfoque para tu aplicación.
Mensajes de proto-plus frente a protobuf
La canalización del generador de código integra proto-plus como una forma de mejorar la ergonomía de la interfaz de mensajes de protobuf haciendo que se comporten más como objetos estándar de Python. Sin embargo, esto significa que el uso de proto-plus introduce una sobrecarga de rendimiento.
Rendimiento de Proto-plus
Uno de los beneficios principales de proto-plus es que convierte mensajes de protobuf y tipos conocidos en tipos de Python integrados a través de un proceso llamado ordenamiento de tipos.
La serialización se produce cuando se accede a un campo en una instancia de mensaje de proto-plus, específicamente cuando se lee o se establece un campo, por ejemplo, en una definición de protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Cuando esta definición se convierte en una clase proto-plus, se ve 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 establece el campo name, el valor se convierte de un tipo str de Python integrado a un tipo string para que el valor sea compatible con el entorno de ejecución de protobuf.
El tiempo que se dedica a realizar estas conversiones de tipo tiene un impacto en el rendimiento lo suficientemente grande como para que decidas, según las necesidades de tu aplicación, si usar mensajes de proto-plus o protobuf.
Casos de uso para mensajes de proto-plus y protobuf
- Casos de uso de mensajes de proto-plus
- Proto-plus ofrece varias mejoras ergonómicas en comparación con los mensajes de protobuf, por lo que son ideales para escribir código legible y fácil de mantener. Como exponen objetos estándar de Python, son más fáciles de usar y comprender.
- Casos de uso de mensajes de Protobuf
- Usa protobufs para casos de uso que requieran un alto rendimiento, específicamente en apps que
necesitan procesar informes grandes con rapidez o que crean solicitudes de mutación con una
gran cantidad de operaciones, por ejemplo, con
BatchJobServiceoOfflineUserDataJobService.
Cambia los tipos de mensajes 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, puedes
cambiar entre los dos tipos de forma dinámica con las utilidades que ofrece la biblioteca
cliente. Usa la misma clase de mensaje Dog que usaste antes:
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 de proto-plus está documentada en detalle, y en las siguientes secciones se destacan las diferencias clave que afectan los casos de uso comunes de la biblioteca cliente de Google Ads.
Serialización de bytes
- Mensajes de proto-plus
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Mensajes de Protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Serialización de JSON
- Mensajes de 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 de protobuf. Cuando uses mensajes de proto-plus,
conviértelos en mensajes de protobuf para usar el ayudante:
- Mensajes de 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)
Enums
Las enumeraciones expuestas por los mensajes de proto-plus son instancias del tipo
enum integrado de Python y, por lo tanto, heredan una serie de métodos
convenientes.
Recuperación de tipos de enumeración
Cuando usas el método GoogleAdsClient.get_type para recuperar enumeraciones, los mensajes
que se devuelven son un poco diferentes según si usas
mensajes de proto-plus o protobuf. Por ejemplo:
- Mensajes de proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Mensajes de Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Para simplificar la recuperación de las enumeraciones, hay un atributo de conveniencia en
las instancias de GoogleAdsClient que tiene una interfaz coherente, independientemente del
tipo de mensaje que uses:
val = client.enums.CampaignStatusEnum.PAUSED
Recuperación de valores de enum
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 de 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 # 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"))
Recuperación de nombres de enumeraciones
A veces, es útil conocer el nombre de un campo de tipo enum. Por ejemplo, cuando
lees objetos de la API, es posible que quieras saber a qué estado de la campaña corresponde
el número entero 3:
- Mensajes de 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 print(status_enum.CampaignStatus.Name(campaign.status))
Campos repetidos
Como se describe en la documentación de proto-plus, los campos repetidos suelen ser equivalentes a las listas con tipo, lo que significa que se comportan casi de forma idéntica a un list.
Agrega valores a campos escalares repetidos
Cuando agregas valores a campos repetidos de tipo escalar, por ejemplo, campos string o int64, la interfaz es la misma, independientemente del tipo de mensaje:
- Mensajes de 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 comunes de list, por ejemplo, extend:
- Mensajes de 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"] )
Agrega 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 de 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
En el caso de los campos repetidos escalares y no escalares, puedes asignar listas al campo de diferentes maneras:
- Mensajes de 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 tiene alguno de sus campos configurados.
- Mensajes de proto-plus
# When using proto-plus messages you can check the message for truthiness. is_empty = not bool(campaign)
- Mensajes de Protobuf
is_empty = campaign.ByteSize() == 0
Copia del mensaje
Para los mensajes proto-plus y protobuf, usa 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 mensajes vacíos es el mismo, independientemente del tipo de mensaje que uses. Copias un mensaje vacío en el campo en cuestión. Consulta la sección Copia del mensaje y la guía Campos de mensaje vacíos. En el siguiente ejemplo, se muestra 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 se usan mensajes de proto-plus, los nombres de los campos aparecen automáticamente con un guion bajo
al final si el nombre también es una palabra reservada en Python. En el siguiente ejemplo,
se muestra cómo trabajar con una instancia de 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 él de forma programática.
Primero, instala el módulo:
python -m pip install gapic-generator
Luego, en un REPL o una secuencia de comandos de Python, haz lo siguiente:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Presencia de campos
Debido a que los campos de las instancias de mensajes de protobuf tienen valores predeterminados, no siempre es intuitivo saber si se estableció un campo o no.
- Mensajes de 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 estableció un submensaje, un campo oneof o un campo escalar optional en un mensaje, incluso si se estableció en un valor predeterminado.
(Llamar a HasField en campos escalares no opcionales en proto3 genera una
ValueError).
Métodos de mensajes de Protobuf
La interfaz de mensajes de protobuf incluye algunos métodos de conveniencia que no forman parte de la interfaz de proto-plus. Sin embargo, puedes acceder a ellos convirtiendo un mensaje de proto-plus en su contraparte de 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()
Issue Tracker
Si tienes alguna pregunta sobre estos cambios o algún problema para migrar a la versión más reciente de la biblioteca, envía un informe en la Herramienta de seguimiento de errores.