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
BatchJobServiceouOfflineUserDataJobService.
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.