Com o parâmetro de configuração use_proto_plus
, é possível especificar se você
quer que a biblioteca retorne
mensagens proto-plus ou
mensagens protobuf (em inglês). Para saber 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 fundamentada.
Proto-plus e mensagens protobuf
O pipeline do gerador de código integra o proto-plus como uma maneira de melhorar a ergonomia da interface de mensagem protobuf, fazendo com que elas se comportem mais como objetos nativos do Python. No entanto, isso significa que o uso do proto-plus introduz uma sobrecarga de desempenho.
Desempenho do proto-plus
Um dos principais benefícios do proto-plus é que ele converte mensagens protobuf e tipos conhecidos em tipos Python nativos por meio de um processo chamado marshaling de tipo.
O marshalling 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 protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Quando essa definição é convertida em uma classe proto-plus, ela fica 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
Python str
nativo para um tipo string
para
que o valor seja compatível com o tempo de execução do protobuf.
Com base nas nossas análises de performance, determinamos que o tempo gasto fazendo esse tipo de conversão tem um impacto de performance grande o suficiente para que os usuários decidam, com base nas necessidades deles, se vão usar ou não mensagens protobuf.
Casos de uso para mensagens proto-plus e protobuf
- Casos de uso de mensagens proto-plus
- O Proto-plus oferece várias melhorias ergonômicas em relação às mensagens protobuf, por isso elas são ideais para escrever um código legível e de fácil manutenção. Como eles expõem objetos Python nativos, são mais fáceis de usar e entender.
- Casos de uso de mensagens do protobuf
- Use protobufs para casos de uso sensíveis à performance, especificamente em apps
que precisam processar relatórios grandes rapidamente ou que criam solicitações de mutação com um
grande número de operações, por exemplo, com
BatchJobService
ouOfflineUserDataJobService
.
Como alterar dinamicamente os tipos de mensagens
Depois de selecionar o tipo de mensagem adequado para seu app, talvez seja necessário usar o outro tipo para um fluxo de trabalho específico. Nesse caso, é
fácil alternar entre os dois tipos dinamicamente usando utilitários oferecidos pela
biblioteca de cliente. Use a mesma classe de mensagem Dog
mostrada 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 está documentada em detalhes, mas aqui vamos destacar algumas diferenças importantes que afetam casos de uso comuns da biblioteca de clientes do Google Ads.
Serialização de bytes
- Mensagens Proto-plus
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Mensagens do 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 de máscara de campo fornecido pelo 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 por 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 de 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 do protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Para simplificar a recuperação de tipos enumerados, há um atributo de conveniência nas
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 o ID do campo de um determinado tipo enumerado. Por
exemplo, PAUSED
no 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 tipo enumerado
Às vezes, é útil saber o nome de um campo de enumeração. Por exemplo, ao
ler objetos da API, talvez você queira saber a que 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
proto-plus,
os campos repetidos geralmente são equivalentes a listas digitadas, o que significa que eles
se comportam quase da mesma forma que um list
.
Anexar valores a campos escalares repetidos
Ao adicionar valores a campos escalar
de tipo repetidos, por exemplo,
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 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"])
Anexar tipos de mensagens a campos repetidos
Se o campo repetido não for um tipo escalar, o comportamento ao adicioná-los 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
Atribuir campos repetidos
Para campos escalares e não escalares repetidos, é possível atribuir listas ao campo de diferentes maneiras:
- 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 dela 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 que você está usando. Você só precisa copiar uma mensagem vazia no campo em questão. Consulte a seção Texto da mensagem e 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 de campos aparecem automaticamente com um
sublinha sublinhado se o nome também for uma palavra reservada no Python. Confira um
exemplo de como trabalhar com uma instância de Asset
:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
A lista completa de nomes reservados é criada no módulo do gerador gapic. Ele também pode ser acessado de maneira programática.
Primeiro, instale o módulo:
python -m pip install gapic-generator
Em seguida, em um script REPL ou Python:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Presença de campo
Como os campos nas instâncias de mensagens do Protobuf têm valores padrão, não é sempre intuitivo saber se um campo foi definido ou não.
- Mensagens Proto-plus
# Use the "in" operator. has_field = "name" in campaign
- Mensagens do protobuf
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
A interface de classe
Message
do protobuf 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 do Protobuf
A interface de mensagens protobuf inclui alguns métodos de conveniência que não fazem parte da interface proto-plus. No entanto, é fácil acessá-los convertendo uma mensagem proto-plus na 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 alguma dúvida sobre essas mudanças ou problemas na migração para a versão mais recente da biblioteca, registre um problema no nosso rastreador.