Lorsque vous utilisez gRPC avec python, vous utiliserez le type protocolbuffer (pb2). Il y a quelques points à prendre en compte lors du traitement de ce type de tampon de protocole, je vais donc le résumer dans l'article.
Par exemple, si vous avez la définition de proto suivante: Conception simple avec une seule méthode.
user.proto
service UserService {
rpc GetUser(GetUserRequest) returns (User) {}
}
message Size {
int32 height = 1;
int32 weight = 2;
}
message User {
string id = 1;
string name = 2;
Size size = 3;
}
message GetUserRequest {
string user_id = 1;
}
Ce qui suit est un exemple d'implémentation côté serveur de UserService utilisant le fichier proto ci-dessus.
import user_pb2
class UserService():
def GetUser(self, request, context):
#obtenir l'utilisateur de db
db_user = db.get(request.user_id)
#Définir la taille et ajouter de la valeur
size = user_pb2.Size()
size.height = db_user.height
size.weight = db_user.weight
#Définissez l'utilisateur, ajoutez de la valeur et retournez
user = user_pb2.User()
user.id = db_user.id
user.name = db_user.name
user.size = size
return user
Lorsque j'exécute la méthode GetUser ci-dessus, j'obtiens une erreur avec TypeError. Le problème est l'avant-dernière ligne de code ʻuser.size = size`.
La taille, qui est un type d'objet du type Taille, est identique au type de taille défini dans le type Utilisateur, mais si vous l'affectez tel quel, une erreur se produira. La méthode utilisée ici est CopyFrom. En réécrivant la partie problématique du code ci-dessus comme suit, le code sera exécuté sans TypeError.
import user_pb2
class UserService():
def GetUser(self, request, context):
#obtenir l'utilisateur de db
db_user = db.get(request.user_id)
#Définir la taille et ajouter de la valeur
size = user_pb2.Size()
size.height = db_user.height
size.weight = db_user.weight
#Définissez l'utilisateur, ajoutez de la valeur et retournez
user = user_pb2.User()
user.id = db_user.id
user.name = db_user.name
user.size.CopyFrom(size)
return user
Même si vous comparez à l'aide de la méthode Type, il est difficile de le remarquer car l'objet de taille est un type de taille, mais lorsque vous l'affectez en tant que type de tampon de protocole, vous ne pouvez pas l'affecter correctement sauf si vous utilisez CopyFrom.
Même avec des définitions répétées, il y a quelques points à prendre en compte lors de l'attribution. Ceci est expliqué à l'aide du fichier proto suivant, qui est une réécriture du UserService précédent.
User.proto
service UserService {
rpc GetUser(GetUserRequest) returns (User) {}
}
message Item {
string id = 1;
string name = 2;
}
message User {
string id = 1;
string name = 2;
repeated Item items = 3;
}
message GetUserRequest {
string user_id = 1;
}
J'ai changé la taille en un type répété appelé éléments. Vous trouverez ci-dessous le code UserService.
import user_pb2
class UserService():
def GetUser(self, request, context):
#obtenir l'utilisateur de db
db_user = db.get(request.user_id)
#Définissez plusieurs éléments et créez une liste d'éléments
item1 = user_pb2.Item()
item1.id = '1'
item1.name = 'item1'
item2 = user_pb2.Item()
item2.id = '2'
item2.name = 'item2'
items = [item1, item2]
#Définissez l'utilisateur, ajoutez de la valeur et retournez
user = user_pb2.User()
user.id = db_user.id
user.name = db_user.name
user.items = items
return user
Lorsque j'exécute le code ci-dessus, j'obtiens toujours un TypeError. La partie problématique est également la partie de ʻuser.items = items`. Utilisez la méthode extend pour affecter à un champ répété.
user.items.extend(items)
En utilisant extend comme décrit ci-dessus, il est possible de définir la valeur sur le type du tableau.
J'ai vérifié sur la page officielle de google etc. pourquoi il est nécessaire de le gérer comme ça, mais cela n'a pas été bien expliqué. Le tampon de protocole semble avoir une habitude sur Python, alors utilisez-le avec prudence!
Recommended Posts