La versione 14.0.0
della libreria client Python introduce un nuovo parametro di configurazione richiesto denominato use_proto_plus
che specifica se la libreria deve restituire i messaggi proto-plus o i messaggi protobuf. Per i dettagli su come impostare questo parametro, consulta la documentazione sulla configurazione.
Questa sezione descrive le implicazioni in termini di prestazioni della scelta dei tipi di messaggi da utilizzare. Pertanto, ti consigliamo di leggere e comprendere le opzioni per prendere una decisione consapevole. Tuttavia, se vuoi eseguire l'upgrade alla versione 14.0.0
senza apportare modifiche al codice, puoi impostare use_proto_plus
su True
per evitare di danneggiare le modifiche all'interfaccia.
Messaggi Proto-plus e protobuf
Nella versione 10.0.0
è stata eseguita la migrazione della libreria client Python a una nuova pipeline del generatore di codice che integrava proto-plus per migliorare l'ergonomia dell'interfaccia del messaggio protobuf rendendola più simile agli oggetti Python nativi. Il compromesso di questo miglioramento è che il protoplus
introduce l'overhead in termini di prestazioni.
Prestazioni con proto-plus
Uno dei vantaggi principali di proto-plus è che converte i messaggi protobuf e i tipi ben noti in tipi Python nativi tramite un processo chiamato marshalling dei tipi.
Il marshalling si verifica quando si accede a un campo in un'istanza di messaggio con proto+, in particolare quando un campo viene letto o impostato, ad esempio in una definizione di protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Quando questa definizione viene convertita in una classe proto-plus, dovrebbe avere il seguente aspetto:
import proto
class Dog(proto.Message):
name = proto.Field(proto.STRING, number=1)
Puoi quindi inizializzare la classe Dog
e accedere al relativo campo name
come faresti con qualsiasi altro oggetto Python:
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
Durante la lettura e l'impostazione del campo name
, il valore viene convertito da un tipo str
nativo di Python a un tipo string
in modo che il valore sia compatibile con il runtime protobuf.
Nell'analisi che abbiamo condotto dopo il rilascio della versione 10.0.0
, abbiamo stabilito che il tempo dedicato all'esecuzione di questi tipi di conversioni ha un impatto sulle prestazioni sufficientemente elevato da offrire agli utenti la possibilità di utilizzare i messaggi protobuf.
Casi d'uso per messaggi proto-plus e protobuf
- Casi d'uso di messaggi con protocollo Plus
- Proto-plus offre una serie di miglioramenti ergonomici rispetto ai messaggi protobuf, per cui sono ideali per scrivere codice gestibile e leggibile. Poiché espongono oggetti Python nativi, sono più facili da usare e comprendere.
- Casi d'uso dei messaggi Protobuf
- Utilizza i protobuf per casi d'uso sensibili alle prestazioni, in particolare nelle app che devono elaborare rapidamente report di grandi dimensioni o che creano richieste di modifica con un numero elevato di operazioni, ad esempio con
BatchJobService
oOfflineUserDataJobService
.
Modifica dinamica dei tipi di messaggi
Dopo aver selezionato il tipo di messaggio appropriato per la tua app, potresti scoprire
che devi utilizzare l'altro tipo per un flusso di lavoro specifico. In questo caso, è facile passare da un tipo all'altro in modo dinamico utilizzando le utilità offerte dalla libreria client. Stai utilizzando la stessa classe di messaggi Dog
indicata sopra:
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)
Differenze nell'interfaccia dei messaggi Protobuf
L'interfaccia proto-plus è documentata in dettaglio, ma qui evidenzieremo alcune differenze chiave che interessano i casi d'uso comuni della libreria client di Google Ads.
Serializzazione dei byte
- Messaggi con più protocollo
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Messaggi Protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Serializzazione JSON
- Messaggi con più protocollo
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Messaggi Protobuf
from google.protobuf.json_format import MessageToJson, Parse serialized = MessageToJson(campaign) deserialized = Parse(serialized, campaign)
Maschere dei campi
Il metodo helper della maschera di campo fornito da api-core è progettato per utilizzare istanze di messaggio protobuf. Quindi, quando utilizzi messaggi proto-plus, convertili in messaggi protobuf per utilizzare l'helper:
- Messaggi con più protocollo
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)
- Messaggi Protobuf
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Enum
Le enum esposte dai messaggi con più proto sono istanze del tipo enum
nativo di Python, perciò ereditano un certo numero di metodi di convenienza.
Recupero tipo di enum
Quando utilizzi il metodo GoogleAdsClient.get_type
per recuperare le enum, i messaggi
restituiti sono leggermente diversi a seconda che tu stia utilizzando
messaggi proto-plus o protobuf. Ad esempio:
- Messaggi con più protocollo
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Messaggi Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Per semplificare il recupero delle enum, è disponibile un attributo di convenienza nelle istanze GoogleAdsClient
con un'interfaccia coerente, indipendentemente dal tipo di messaggio utilizzato:
val = client.enums.CampaignStatusEnum.PAUSED
Recupero valore enum
A volte è utile conoscere il valore o l'ID campo di una determinata enum, ad esempio PAUSED
nella CampaignStatusEnum
corrisponde a 3
:
- Messaggi con più protocollo
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the value of campaign status print(campaign.status.value)
- Messaggi 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))
Recupero nome enum
A volte è utile conoscere il nome di un campo enum. Ad esempio, durante la lettura di oggetti dall'API, potresti voler sapere a quale stato della campagna corrisponde l'int 3
:
- Messaggi con più protocollo
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the name of campaign status print(campaign.status.name)
- Messaggi 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)
Campi ripetuti
Come descritto nella documentazione proto-plus, i campi ripetuti sono generalmente equivalenti agli elenchi digitati, il che significa che si comportano quasi in modo identico a list
.
Aggiunta a campi scalari ripetuti
Quando aggiungi valori a campi di tipo scala ripetuti, ad esempio campi string
o int64
, l'interfaccia è la stessa indipendentemente dal tipo di messaggio:
- Messaggi con più protocollo
ad.final_urls.append("https://www.example.com")
- Messaggi Protobuf
ad.final_urls.append("https://www.example.com")
Sono inclusi anche tutti gli altri metodi list
comuni, ad esempio extend
:
- Messaggi con più protocollo
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Messaggi Protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Aggiunta di tipi di messaggi ai campi ripetuti
Se il campo ripetuto non è un tipo scalar, il comportamento quando li aggiungi a campi ripetuti è leggermente diverso:
- Messaggi con più protocollo
frequency_cap = client.get_type("FrequencyCapEntry") frequency_cap.cap = 100 campaign.frequency_caps.append(frequency_cap)
- Messaggi Protobuf
# The add method initializes a message and adds it to the repeated field frequency_cap = campaign.frequency_caps.add() frequency_cap.cap = 100
Assegnazione di campi ripetuti
Per i campi ripetuti scalari e non scalabili, puoi assegnare elenchi al campo in diversi modi:
- Messaggi con più protocollo
# In proto-plus it's possible to use assignment. urls = ["https://www.example.com"] ad.final_urls = urls
- Messaggi 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
Messaggi vuoti
A volte è utile sapere se un'istanza di un messaggio contiene informazioni o se ha impostato uno dei suoi campi.
- Messaggi con più protocollo
# When using proto-plus messages you can simply check the message for # truthiness. is_empty = bool(campaign) is_empty = not campaign
- Messaggi Protobuf
is_empty = campaign.ByteSize() == 0
Copia del messaggio
Per i messaggi proto-plus e protobuf, consigliamo di utilizzare il metodo helper copy_from
nella GoogleAdsClient
:
client.copy_from(campaign, other_campaign)
Campi del messaggio vuoti
La procedura per impostare campi dei messaggi vuoti è la stessa indipendentemente dal tipo di messaggio in uso. Devi solo copiare un messaggio vuoto nel campo in questione. Consulta la sezione Testo del messaggio e la guida Campi messaggio vuoti. Ecco un esempio di come impostare un campo messaggio vuoto:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
Nomi dei campi che sono parole riservate
Quando utilizzi i messaggi proto-plus, i nomi dei campi vengono visualizzati automaticamente con un trattino basso finale se il nome è anche una parola riservata in Python. Ecco un esempio di utilizzo di un'istanza Asset
:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
L'elenco completo dei nomi riservati viene creato nel modulo del generatore gapic. È possibile anche accedervi in modo programmatico.
Innanzitutto, installa il modulo:
python -m pip install gapic-generator
Quindi, in uno script o REPL Python:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Presenza sul campo
Poiché i campi nelle istanze di messaggi protobuf hanno valori predefiniti, non è sempre intuitivo sapere se un campo è stato impostato o meno.
- Messaggi con più protocollo
# Use the "in" operator. has_field = "name" in campaign
- Messaggi Protobuf
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
L'interfaccia della classe protobuf Message
ha un metodo HasField
che determina se il campo in un messaggio è stato impostato, anche se era impostato su un valore predefinito.
Metodi per i messaggi Protobuf
L'interfaccia del messaggio protobuf include alcuni metodi pratici che non fanno parte dell'interfaccia proto-plus; tuttavia, è semplice accedervi convertendo un messaggio proto-plus nella relativa controparte 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())
Monitoraggio problemi
In caso di domande su queste modifiche o su eventuali problemi di migrazione alla versione 14.0.0
della libreria, segnala un problema sul nostro tracker.