La version 14.0.0
de la bibliothèque cliente Python introduit un nouveau paramètre de configuration appelé use_proto_plus
, qui spécifie si la bibliothèque doit renvoyer des messages proto-plus ou des messages protobuf. Pour savoir comment définir ce paramètre, consultez la documentation sur la configuration.
Cette section décrit les implications en termes de choix des types de messages à utiliser. Par conséquent, nous vous recommandons de lire et de comprendre les options afin de prendre une décision éclairée. Toutefois, si vous souhaitez passer à la version 14.0.0
sans modifier le code, vous pouvez définir use_proto_plus
sur True
pour éviter les modifications de l'interface.
Messages Proto-plus et protobuf
Dans la version 10.0.0
, la bibliothèque cliente Python a migré vers un nouveau pipeline de générateur de code qui a intégré proto-plus afin d'améliorer l'ergonomie de l'interface du message protobuf en le faisant ressembler à un objet Python natif. En contrepartie de cette amélioration, proto-plus entraîne une surcharge de performances.
Performances Proto-Plus
L'un des principaux avantages de proto-plus est qu'il convertit les messages protobuf et les types connus en types Python natifs via un processus appelé marshaling de type.
Le marshaling se produit lorsqu'un champ est accessible sur une instance de message proto-plus, en particulier lorsqu'un champ est lu ou défini, par exemple dans une définition protobuf:
syntax = "proto3";
message Dog {
string name = 1;
}
Lorsque cette définition est convertie en classe proto-plus, elle se présente comme suit:
import proto
class Dog(proto.Message):
name = proto.Field(proto.STRING, number=1)
Vous pouvez ensuite initialiser la classe Dog
et accéder à son champ name
comme vous le feriez pour tout autre objet Python:
dog = Dog()
dog.name = "Scruffy"
print(dog.name)
Lors de la lecture et de la définition du champ name
, la valeur est convertie d'un type str
natif en Python en un type string
afin qu'elle soit compatible avec l'environnement d'exécution protobuf.
Dans l'analyse que nous avons menée depuis la version 10.0.0
, nous avons déterminé que le temps consacré à ces conversions de type a un impact en termes de performances suffisamment important pour qu'il soit important de donner aux utilisateurs la possibilité d'utiliser des messages protobuf.
Cas d'utilisation des messages proto-plus et protobuf
- Cas d'utilisation des messages Proto-Plus
- Proto-plus offre un certain nombre d'améliorations ergonomiques par rapport aux messages protobuf. Elles sont donc idéales pour écrire un code lisible et facile à gérer. Étant donné qu'ils exposent des objets Python natifs, ils sont plus faciles à utiliser et à comprendre.
- Cas d'utilisation des messages Protobuf
- Utilisez des tampons de protocole pour les cas d'utilisation sensibles aux performances, en particulier dans les applications qui doivent traiter rapidement des rapports volumineux ou qui compilent des requêtes mutate avec un grand nombre d'opérations, par exemple avec
BatchJobService
ouOfflineUserDataJobService
.
Modifier les types de messages de façon dynamique
Après avoir sélectionné le type de message approprié pour votre application, vous devrez peut-être utiliser l'autre type pour un workflow spécifique. Dans ce cas, il est facile de basculer dynamiquement entre les deux types à l'aide des utilitaires proposés par la bibliothèque cliente. En utilisant la même classe de message Dog
ci-dessus:
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)
Différences entre les interfaces des messages Protobuf
L'interface proto-plus est décrite en détail, mais nous présentons ici quelques différences clés qui affectent les cas d'utilisation courants de la bibliothèque cliente Google Ads.
Sérialisation des octets
- Messages Proto-Plus
serialized = type(campaign).serialize(campaign) deserialized = type(campaign).deserialize(serialized)
- Messages Protobuf
serialized = campaign.SerializeToString() deserialized = campaign.FromString(serialized)
Sérialisation JSON
- Messages Proto-Plus
serialized = type(campaign).to_json(campaign) deserialized = type(campaign).from_json(serialized)
- Messages Protobuf
from google.protobuf.json_format import MessageToJson, Parse serialized = MessageToJson(campaign) deserialized = Parse(serialized, campaign)
Masques de champ
La méthode d'assistance du masque de champ fournie par api-core est conçue pour utiliser des instances de messages protobuf. Par conséquent, lorsque vous utilisez des messages proto-plus, convertissez-les en messages protobuf pour utiliser l'assistant:
- Messages 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)
- Messages Protobuf
from google.api_core.protobuf_helpers import field_mask campaign = client.get_type("Campaign") mask = field_mask(None, campaign)
Enums
Les énumérations exposées par les messages proto-plus sont des instances du type enum
natif de Python et héritent donc d'un certain nombre de méthodes pratiques.
Récupération du type d'énumération
Lorsque vous utilisez la méthode GoogleAdsClient.get_type
pour récupérer des énumérations, les messages renvoyés sont légèrement différents selon que vous utilisez des messages proto-plus ou protobuf. Exemple :
- Messages Proto-Plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
- Messages Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED
Pour faciliter la récupération des énumérations, il existe un attribut pratique sur les instances GoogleAdsClient
avec une interface cohérente, quel que soit le type de message que vous utilisez:
val = client.enums.CampaignStatusEnum.PAUSED
Récupération de la valeur d'énumération
Il est parfois utile de connaître la valeur ou l'ID de champ d'une énumération donnée. Par exemple, PAUSED
sur CampaignStatusEnum
correspond à 3
:
- Messages Proto-Plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the value of campaign status print(campaign.status.value)
- Messages 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))
Récupération du nom de l'énumération
Il est parfois utile de connaître le nom d'un champ d'énumération. Par exemple, lors de la lecture d'objets à partir de l'API, vous pouvez savoir à quel état de campagne correspond l'int 3
.
- Messages Proto-Plus
campaign = client.get_type("Campaign") campaign.status = client.enums.CampaignStatusEnum.PAUSED # To read the name of campaign status print(campaign.status.name)
- Messages 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)
Champs répétés
Comme décrit dans la documentation de proto-plus, les champs répétés sont généralement équivalents aux listes saisies, ce qui signifie qu'ils se comportent presque de la même manière que list
.
Ajouter aux champs scalaires répétés
Lors de l'ajout de valeurs aux champs répétés de type scalaire, par exemple les champs string
ou int64
, l'interface est la même quel que soit le type de message:
- Messages Proto-Plus
ad.final_urls.append("https://www.example.com")
- Messages Protobuf
ad.final_urls.append("https://www.example.com")
Cela inclut également toutes les autres méthodes list
courantes, telles que extend
:
- Messages Proto-Plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
- Messages Protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Ajouter des types de messages à des champs répétés
Si le champ répété n'est pas un type scalaire, le comportement de son ajout aux champs répétés est légèrement différent:
- Messages Proto-Plus
frequency_cap = client.get_type("FrequencyCapEntry") frequency_cap.cap = 100 campaign.frequency_caps.append(frequency_cap)
- Messages Protobuf
# The add method initializes a message and adds it to the repeated field frequency_cap = campaign.frequency_caps.add() frequency_cap.cap = 100
Attribuer des champs répétés
Pour les champs répétés scalaires et non scalaires, vous pouvez attribuer des listes au champ de différentes manières:
- Messages Proto-Plus
# In proto-plus it's possible to use assignment. urls = ["https://www.example.com"] ad.final_urls = urls
- Messages 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
Messages vides
Il est parfois utile de savoir si une instance de message contient des informations ou si l'un de ses champs est défini.
- Messages Proto-Plus
# When using proto-plus messages you can simply check the message for # truthiness. is_empty = bool(campaign) is_empty = not campaign
- Messages Protobuf
is_empty = campaign.ByteSize() == 0
Copie du message
Pour les messages proto-plus et protobuf, nous vous recommandons d'utiliser la méthode d'assistance copy_from
sur GoogleAdsClient
:
client.copy_from(campaign, other_campaign)
Champs de message vides
Le processus de définition des champs de message vides est le même, quel que soit le type de message que vous utilisez. Il vous suffit de copier un message vide dans le champ en question. Consultez la section Copie de message ainsi que le guide sur les champs de message vides. Voici un exemple de définition d'un champ de message vide:
client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))
Noms de champs qui sont des mots réservés
Lorsque vous utilisez des messages proto-plus, les noms de champs apparaissent automatiquement avec un trait de soulignement de fin si le nom est également un mot réservé en Python. Voici un exemple de travail avec une instance Asset
:
asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE
La liste complète des noms réservés est construite dans le module du générateur de gapics. Il est également accessible de manière automatisée.
Commencez par installer le module:
python -m pip install gapic-generator
Ensuite, dans un REPL Python ou un script:
import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)
Présence sur le terrain
Étant donné que les champs des instances de message tampon de protocole sont associés à des valeurs par défaut, il n'est pas toujours intuitif de savoir si un champ a été défini ou non.
- Messages Proto-Plus
# Use the "in" operator. has_field = "name" in campaign
- Messages Protobuf
campaign = client.get_type("Campaign") # Determines whether "name" is set and not just an empty string. campaign.HasField("name")
L'interface de la classe protobuf Message
comporte une méthode HasField
qui détermine si le champ d'un message a été défini, même s'il a été défini sur une valeur par défaut.
Méthodes de message Protobuf
L'interface du message protobuf inclut des méthodes pratiques qui ne font pas partie de l'interface proto-plus. Toutefois, il est simple d'y accéder en convertissant un message proto-plus en son équivalent 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())
Outil de suivi des problèmes
Si vous avez des questions sur ces modifications ou si vous rencontrez des problèmes pour migrer vers la version 14.0.0
de la bibliothèque, signalez un problème sur notre outil de suivi.