A versão
14.0.0
da biblioteca de cliente Python introduz um novo parâmetro de configuração obrigatório
chamado use_proto_plus
, que especifica se você quer que a biblioteca retorne
mensagens proto-plus ou
mensagens protobuf. Para detalhes sobre
como definir esse parâmetro, consulte os documentos de configuração.
Nesta seção, descrevemos as implicações de desempenho da escolha dos tipos de
mensagens a serem usadas. Portanto, recomendamos que você leia e entenda
as opções para tomar uma decisão informada. No entanto, se você quiser
fazer upgrade para a versão 14.0.0
sem fazer mudanças no código, defina
use_proto_plus
como True
para evitar alterações na interface.
Mensagens Proto-plus x protobuf
Na versão 10.0.0
, a biblioteca de cliente Python migrou para um novo pipeline gerador de
código que integrou o
proto-plus como uma maneira de melhorar
a ergonomia da interface de mensagens protobuf fazendo com que eles se comportem mais
como objetos nativos do Python. A desvantagem dessa melhoria é que o proto-plus
introduz sobrecarga de desempenho.
Desempenho Proto-plus
Um dos principais benefícios do proto-plus é que ele converte mensagens protobuf e tipos conhecidos em tipos nativos do Python usando um processo chamado marshaling de tipo.
O marshaling ocorre quando um campo é acessado em uma instância de mensagem proto-plus, especificamente quando um campo é lido ou definido, por exemplo, em uma definição de protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Quando essa definição é convertida em uma classe proto-plus, ela ficaria mais ou menos assim:
import proto
class Dog(proto.Message):
name = proto.Field(proto.STRING, number=1)
Em seguida, inicialize a classe Dog
e acesse o campo name
como faria
com qualquer outro objeto Python:
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
Ao ler e definir o campo name
, o valor é convertido de um tipo
str
nativo do Python para um tipo string
para
que o valor seja compatível com o ambiente de execução protobuf.
Na análise que realizamos desde o lançamento da versão 10.0.0
, determinamos que o tempo gasto fazendo essas conversões de tipo tem um impacto de performance grande
o suficiente para que seja importante oferecer aos usuários a opção de usar mensagens
protobuf.
Casos de uso para mensagens proto-plus e protobuf
- Casos de uso de mensagens Proto-plus
- O Protoplus oferece várias melhorias ergonômicas em relação às mensagens protobuf. Portanto, elas são ideais para escrever códigos legíveis e fáceis de manter. Por exporem objetos Python nativos, são mais fáceis de usar e entender.
- Casos de uso de mensagens protobuf
- Use protobufs para casos de uso que dependem do desempenho, principalmente em apps
que precisam processar relatórios grandes rapidamente ou que criam solicitações mutate com um
grande número de operações, por exemplo, com
BatchJobService
ouOfflineUserDataJobService
.
Mudança dinâmica dos tipos de mensagem
Depois de selecionar o tipo de mensagem adequado para seu app, talvez você descubra
que precisa usar o outro tipo para um fluxo de trabalho específico. Nesse caso, é fácil alternar entre os dois tipos dinamicamente usando os utilitários oferecidos pela biblioteca de cliente. Usando a mesma classe de mensagem Dog
acima:
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)
Diferenças na interface de mensagens protobuf
A interface proto-plus é documentada em detalhes, mas destacamos algumas diferenças importantes que afetam casos de uso comuns da biblioteca de cliente do Google Ads.
Serialização de bytes
- Mensagens Proto-plus
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Mensagens protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Serialização JSON
- Mensagens Proto-plus
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Mensagens protobuf
from google.protobuf.json_format import MessageToJson, Parse serialized = MessageToJson(campaign) deserialized = Parse(serialized, campaign)
Máscaras de campo
O método auxiliar da máscara de campo fornecido pela api-core foi projetado para usar instâncias de mensagem protobuf. Portanto, ao usar mensagens proto-plus, converta-as em mensagens protobuf para usar o auxiliar:
- Mensagens 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)
- Mensagens protobuf
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Enums
Os tipos enumerados expostos pelas mensagens proto-plus são instâncias do tipo
enum
nativo do Python e,
portanto, herdam vários métodos de conveniência.
Recuperação do tipo de enumeração
Ao usar o método GoogleAdsClient.get_type
para extrair tipos enumerados, as mensagens
retornadas são um pouco diferentes, dependendo se você está usando
mensagens proto-plus ou protobuf. Exemplo:
- Mensagens Proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Mensagens protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Para simplificar a recuperação de tipos enumerados, há um atributo de conveniência em
instâncias de GoogleAdsClient
que tem uma interface consistente, independente do
tipo de mensagem que você está usando:
val = client.enums.CampaignStatusEnum.PAUSED
Recuperação de valor de tipo enumerado
Às vezes, é útil saber o valor, ou ID do campo, de um determinado tipo enumerado.
Por exemplo, PAUSED
em CampaignStatusEnum
corresponde a 3
:
- Mensagens Proto-plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the value of campaign status print(campaign.status.value)
- Mensagens 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))
Recuperação de nome de enumeração
Às vezes, é útil saber o nome de um campo de enumeração. Por exemplo, ao ler objetos da API, talvez você queira saber a qual status de campanha o int 3
corresponde:
- Mensagens Proto-plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the name of campaign status print(campaign.status.name)
- Mensagens 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
Conforme descrito nos documentos do
proto-plus,
os campos repetidos geralmente são equivalentes a listas tipadas, o que significa que
eles se comportam de maneira quase idêntica a um list
.
Anexando a campos escalares repetidos
Quando você adiciona valores a campos de tipo escalar repetidos, como string
ou int64
, a interface é a mesma, independentemente do tipo de mensagem:
- Mensagens Proto-plus
ad.final_urls.append("https://www.example.com")
- Mensagens protobuf
ad.final_urls.append("https://www.example.com")
Isso também inclui todos os outros métodos list
comuns, como extend
:
- Mensagens Proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Mensagens protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Como anexar tipos de mensagens a campos repetidos
Se o campo repetido não for de tipo escalar, o comportamento ao adicioná-lo a campos repetidos será um pouco diferente:
- Mensagens Proto-plus
frequency_cap = client.get_type("FrequencyCapEntry") frequency_cap.cap = 100 campaign.frequency_caps.append(frequency_cap)
- Mensagens protobuf
# The add method initializes a message and adds it to the repeated field frequency_cap = campaign.frequency_caps.add() frequency_cap.cap = 100
Como atribuir campos repetidos
Para campos repetidos escalares e não escalares, é possível atribuir listas ao campo de maneiras diferentes:
- Mensagens Proto-plus
# In proto-plus it's possible to use assignment. urls = ["https://www.example.com"] ad.final_urls = urls
- Mensagens 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
Mensagens vazias
Às vezes, é útil saber se uma instância de mensagem contém informações ou se algum dos campos está definido.
- Mensagens Proto-plus
# When using proto-plus messages you can simply check the message for # truthiness. is_empty = bool(campaign) is_empty = not campaign
- Mensagens protobuf
is_empty = campaign.ByteSize() == 0
Texto da mensagem
Para mensagens proto-plus e protobuf, recomendamos usar o método auxiliar copy_from
no GoogleAdsClient
:
client.copy_from(campaign, other_campaign)
Campos de mensagem vazios
O processo para definir campos de mensagem vazios é o mesmo, independentemente do tipo de mensagem usado. Basta copiar uma mensagem vazia no campo em questão. Consulte a seção Cópia da mensagem, bem como o guia Campos de mensagem vazios. Confira um exemplo de como definir um campo de mensagem vazio:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
Nomes de campos que são palavras reservadas
Ao usar mensagens proto-plus, os nomes dos campos vão aparecer automaticamente com um
sublinhado final se o nome também for uma palavra reservada no Python. Confira um
exemplo de como trabalhar com uma instância do Asset
:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
A lista completa de nomes reservados é criada no módulo gerador gapic. Ele também pode ser acessado programaticamente.
Primeiro, instale o módulo:
python -m pip install gapic-generator
Depois, em um REPL ou script Python:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Presença de campo
Como os campos nas instâncias de mensagem protobuf têm valores padrão, nem sempre é intuitivo saber se um campo foi definido ou não.
- Mensagens Proto-plus
# Use the "in" operator. has_field = "name" in campaign
- Mensagens protobuf
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
A interface da classe protobuf
Message
tem um método HasField
que determina se o campo em uma
mensagem foi definido, mesmo que tenha sido definido como um valor padrão.
Métodos de mensagem protobuf
A interface de mensagens protobuf inclui alguns métodos de conveniência que não fazem parte da interface proto-plus. No entanto, é simples acessá-los convertendo uma mensagem proto-plus em uma 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())
Issue tracker
Se você tiver dúvidas sobre essas mudanças ou problemas na migração para a
versão 14.0.0
da biblioteca, registre um
problema no nosso
rastreador.