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. Para detalhes sobre como
definir esse parâmetro, consulte os documentos de configuração.
Nesta seção, descrevemos as implicações de desempenho de cada opção para que você possa escolher a melhor abordagem para seu aplicativo.
Mensagens proto-plus versus protobuf
O pipeline do gerador de código integra o proto-plus como uma maneira de melhorar a ergonomia da interface de mensagens do protobuf, fazendo com que elas se comportem mais como objetos Python padrão. 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 integrados do Python por meio de um processo chamado marshaling de tipo.
A organização 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 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 str integrado do Python para um tipo string para que o valor seja compatível com o ambiente de execução do protobuf.
O tempo gasto para realizar essas conversões de tipo tem um impacto de desempenho grande o suficiente para que você decida, com base nas necessidades do aplicativo, se deve usar mensagens proto-plus ou protobuf.
Casos de uso para mensagens proto-plus e protobuf
- Casos de uso de mensagens do Proto-plus
- O Proto-plus oferece várias melhorias ergonômicas em relação às mensagens do protobuf, por isso é ideal para escrever códigos fáceis de manter e ler. Como eles expõem objetos Python padrão, são mais fáceis de usar e entender.
- Casos de uso de mensagens do Protobuf
- Use protobufs para casos de uso que dependem de 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.
Alternar tipos de mensagem dinamicamente
Depois de selecionar o tipo de mensagem apropriado para seu app, talvez você precise usar o outro tipo para um fluxo de trabalho específico. Nesse caso, é possível
alternar entre os dois tipos dinamicamente usando utilitários oferecidos pela biblioteca
de cliente. Usando a mesma classe de mensagem Dog de 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)
Diferenças na interface de mensagens do Protobuf
A interface proto-plus está documentada em detalhes, e as seções a seguir destacam as principais diferenças que afetam os 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 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 do 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 por api-core foi
projetado para usar instâncias de mensagem protobuf. 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 do Protobuf
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Tipos enumerados
Os tipos enumerados expostos por mensagens proto-plus são instâncias do tipo
enum integrado do Python e, portanto, herdam vários métodos
de conveniência.
Recuperação de tipo enumerado
Ao usar o método GoogleAdsClient.get_type para recuperar 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 em instâncias GoogleAdsClient que tem uma interface consistente, seja qual for o 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 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 do 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"))
Recuperação de nome de tipo enumerado
Às vezes, é útil saber o nome de um campo de tipo enumerado. Por exemplo, ao ler objetos da API, talvez você queira saber a qual status de campanha o número inteiro 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 do 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
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.
Anexar valores a campos escalares repetidos
Ao adicionar valores a campos repetidos de
tipo escalar, como campos string
ou int64, a interface é a mesma, independentemente do tipo de mensagem:
- Mensagens proto-plus
ad.final_urls.append("https://www.example.com")
- Mensagens do Protobuf
ad.final_urls.append("https://www.example.com")
Isso também inclui todos os outros métodos comuns de list, por exemplo, extend:
- Mensagens proto-plus
ad.final_urls.extend( ["https://www.example.com", "https://www.example.com/2"] )
- Mensagens do Protobuf
ad.final_urls.extend( ["https://www.example.com", "https://www.example.com/2"] )
Adicionar tipos de mensagem ao final de campos repetidos
Se o campo repetido não for um 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 do 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 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 do 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 alguma informação ou se algum dos campos dela está definido.
- Mensagens proto-plus
# When using proto-plus messages you can check the message for truthiness. is_empty = not bool(campaign)
- Mensagens do Protobuf
is_empty = campaign.ByteSize() == 0
Texto da mensagem
Para mensagens proto-plus e protobuf, use 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ê copia uma mensagem vazia no campo em questão. Consulte a seção Cópia da mensagem e o guia Campos de mensagem vazios. O exemplo a seguir mostra 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 campo aparecem automaticamente com um sublinhado
no final se o nome também for uma palavra reservada em Python. O exemplo a seguir
mostra como trabalhar com uma instância Asset:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
A lista completa de nomes reservados é criada no módulo gerador de gapic. Ele também pode ser acessado de forma programática.
Primeiro, instale o módulo:
python -m pip install gapic-generator
Em seguida, em um REPL ou script do Python:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Presença de campo
Como os campos nas instâncias de mensagem do 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 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 uma submensagem, um campo oneof ou um campo escalar optional
em uma mensagem foi definido, mesmo que tenha sido definido como um valor padrão.
Chamar HasField em campos escalares não opcionais em proto3 gera um
ValueError.
Métodos de mensagem do Protobuf
A interface de mensagens do protobuf inclui alguns métodos de conveniência que não fazem parte da interface do proto-plus. No entanto, é possível acessá-los convertendo uma mensagem do proto-plus na contraparte do 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
Se você tiver dúvidas sobre essas mudanças ou problemas para migrar para a versão mais recente da biblioteca, registre um problema no Issue Tracker.