Cours de développement Python avancé
Chapitre
>
Niveau
Modules de sérialisation
Module de structures
Objectif
Configurez la répartition finale des données pour la nouvelle exploitation agricole à l’aide du module struct.
Au bout de la route se trouve une station-service qui gère la nouvelle exploitation agricole déjà construite et les cultures déjà plantées. Ici, nous allons inspecter et traiter les données relatives aux cultures déjà plantées et au rendement projeté de l’exploitation. Comme dans les autres niveaux de ce chapitre, nous travaillerons sur la sérialisation et la désérialisation des données, en introduisant un dernier module nommé struct.
Le module struct propose une série de fonctions de sérialisation qui emballent les données au format binaire. Contrairement aux autres modules avec lesquels nous avons travaillé, il offre toutefois un contrôle plus précis sur la structure des données lors de la sérialisation et de la désérialisation, ce qui le rend plus polyvalent. Utilisez import struct pour accéder aux fonctions suivantes que nous utiliserons pour traiter les données :
struct.calcsize(): Détermine combien d’octets sont occupés par une chaîne de format donnée. Elle prend un (1) argument : le format dont vous souhaitez vérifier la taille en octets. Les formats que nous utiliserons sont :- integer : représenté par
'i', c’est le format pour les nombres entiers - float : représenté par
'f', c’est le format pour les nombres décimaux simples - double : représenté par
'd', c’est le format pour les nombres décimaux plus complexes lorsque le format float est insuffisant
- integer : représenté par
struct.pack(): Sérialise les données en binaire, empaquetées dans le format de votre choix. Elle peut prendre deux (2) arguments ou plus : le format à utiliser et les valeurs à sérialiser. Les formats sont ceux décrits précédemment et vous devez les ajouter en fonction du nombre d’arguments fournis.struct.unpack(): Désérialise des données binaires empaquetées. Elle prend deux (2) arguments : le format dans lequel il faut que les données soient comparables à celui utilisé lors de la sérialisation, et les données sérialisées.struct.iter_unpack(): Désérialise des données binaires empaquetées de la même manière questruct.unpack(), mais itère sur chaque bloc de données individuellement à l’aide d’une boucle.struct.pack_into(): Version avancée destruct.pack(), elle prend quatre (4) arguments : le format à utiliser, le tampon de données dans lequel vous souhaitez insérer les données, la position dans le tampon où vous voulez les placer, et enfin les données à empaqueter.struct.unpack_from(): Version avancée destruct.unpack(), elle prend trois (3) arguments : le format à utiliser, le tampon de données dans lequel vous souhaitez extraire les données, et enfin l’emplacement dans le tampon à partir duquel vous voulez désérialiser. Cela vous permet de désérialiser des portions spécifiques des données.
Dirigez-vous vers la marque X lumineuse de la station-service et faites face au bureau. Créez trois (3) variables nommées : integer, float et double. Nous les utiliserons pour vérifier la taille en octets de chaque format à l’aide de la fonction struct.calcsize(). Pour la variable integer, utilisez la fonction avec 'i' comme argument ; pour la variable float, utilisez 'f' comme argument ; et enfin, pour la variable double, utilisez 'd' comme argument. Par exemple : integer = struct.calcsize('i'). Ajoutez les trois (3) variables à la fonction write() déjà écrite.
Dirigez-vous vers la marque X dorée et utilisez la fonction read() pour collecter des données sur la nouvelle exploitation agricole. Notez les points de données et leur format pour une utilisation ultérieure, à savoir : Ressources, Taille et Estimation. Une fois ces informations notées, rendez-vous à la marque X lumineuse sur le tapis bleu et créez une variable nommée blue_data.
Avec la variable blue_data, stockez la valeur de la fonction struct.pack(), en passant comme arguments le format et les valeurs que vous avez notés précédemment. Lors de la rédaction du format, vous devez « empiler » les types de format en une seule unité. Par exemple, le format entier est désigné par 'i' comme indiqué précédemment ; si vous ajoutez trois entiers, vous l’écrivez 'iii'. De même, si vous ajoutez un entier, un float et un double, cela s’écrit 'ifd'. Pour ajouter les données, placez-les individuellement comme arguments. Voici un exemple global :
data_1 = 8 # is an integer data_2 = 2.25 # is a float data_3 = 900.702938103 # is a double blue_data = struct.pack('ifd', data_1, data_2, data_3)
La fonction struct.pack() offre une grande flexibilité, car elle vous permet de définir le format des données et de sérialiser plusieurs points de données à la fois, selon vos besoins. Ajoutez les données précédemment lues en vous basant sur l’exemple ci-dessus. Utilisez la fonction display() avec blue_data comme argument pour afficher les données empaquetées.
Dirigez-vous vers la marque X sombre sur le tapis bleu et faites face au terminal. Créez une variable nommée blue_unpack et stockez-y la valeur de la fonction struct.unpack(), en passant comme arguments le même format utilisé pour empaqueter les données et la variable blue_data. Le format s’écrit de la même manière que pour struct.pack(), ce qui vous permet de désérialiser les données exactement comme vous les avez initialement sérialisées. Utilisez la fonction write() avec blue_unpack comme argument pour vérifier les données que vous avez empaquetées.
Au même endroit, nous utiliserons également la fonction struct.iter_unpack(). Elle prend exactement les mêmes arguments que struct.unpack(), mais ici elle s’utilise dans une boucle for, ce qui nous permet d’itérer sur les données au lieu de tout écrire d’un coup. La fonction s’écrit comme suit :
for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)
Nous utiliserons la fonction speak() pour afficher les valeurs. Pour les arguments manquants de struct.iter_unpack(), ajoutez les mêmes que ceux utilisés précédemment avec struct.unpack(), car ce sont des variantes de la même fonction en termes d’utilisation.
Dirigez-vous vers la marque X dorée sur le tapis rouge et faites face au bureau. Utilisez la fonction read() pour examiner les quantités de récoltes. Notez toutes les quantités et le format de chaque culture. Ensuite, rendez-vous à la marque X lumineuse sur le tapis rouge et créez un objet nommé buffer, en lui assignant la valeur bytearray(16). Il s’agit d’une collection d’octets que nous pouvons adresser avant de la remplir ; pour nos besoins, elle fonctionne comme une banque de données où vous pouvez stocker manuellement les données. Le nombre 16 en argument correspond au nombre d’octets que vous pouvez stocker dans l’objet buffer.
Utilisez la fonction struct.pack_into() pour remplir l’objet buffer que vous avez créé. Il n’est pas nécessaire de créer une variable pour stocker la valeur de cette fonction, car elle insère directement les valeurs dans l’objet buffer. Nous allons utiliser cette fonction pour chacune des valeurs que vous avez notées précédemment et remplir ses arguments en conséquence.
Par exemple, pour la première valeur de récolte fournie, on vous donnera son format, sa position en octets et sa quantité. Ajoutez le format en premier argument, puis l’emplacement dans lequel vous souhaitez sérialiser les octets, en l’occurrence buffer. Pour le troisième argument, indiquez la position à laquelle vous voulez ajouter la valeur dans buffer ; le format détermine le nombre d’octets utilisés, veillez donc à empaqueter des données dans des régions non occupées. Enfin, ajoutez la valeur que vous souhaitez sérialiser et empaqueter dans l’objet buffer.
struct.pack_into('i', buffer, 0, 82)
L’objet buffer contient 16 octets comme indiqué précédemment. Dans le code présenté ci-dessus, le format entier (i) occupe 4 octets et est inséré à la position 0. Cela signifie qu’une fois cette valeur insérée dans buffer, il ne reste que 12 octets disponibles, les positions 0 à 3 étant occupées par la valeur 82. Faites de même pour tous les points de données de récolte que vous avez lus et notés (au total, trois (3)). Utilisez la fonction display() en passant buffer pour afficher les données sérialisées.
Dirigez-vous vers la marque X sombre sur le tapis rouge et faites face au terminal ; ici, nous allons désérialiser les données pour vérifier leur contenu et assurer un stockage correct. Créez trois variables nommées : lettuce, carrots et melons. Nous allons désarchiver les données de chaque point individuel. Pour chaque variable, stockez la valeur de struct.unpack_from() en passant comme arguments les mêmes informations que celles notées pour empaqueter les données. Pour le premier argument, indiquez le format ; pour le deuxième, ajoutez l’objet buffer qui est l’emplacement d’où extraire les données ; enfin, pour le troisième, précisez la position dans buffer à partir de laquelle vous souhaitez désérialiser. Par exemple :
lettuce = struct.unpack_from('i', buffer, 0)
Ces données correspondent à l’exemple de sérialisation précédent. Faites de même pour les deux autres variables et passez lettuce, carrots et melons dans la fonction write() déjà écrite afin de terminer le niveau.