from termcolor import cprint
from dateutil.tz import gettz
import datetime as dt
import locale
locale.setlocale(locale.LC_ALL, ('fr_FR', 'UTF-8'))
tzi = gettz('Europe/Brussels')
cprint('{} {}'.format('danielhagnoul', dt.datetime.now(tz=tzi).isoformat()), 'red')
Lorsqu'un programme a besoin de sauvegarder son état lorsqu'il s'arrête et de récupérer son état lorsqu'il démarre, on peut utiliser le module shelve qui utilise en interne le module pickle pour transformer un objet python complexe en un flux d'octets et inversement.
Le module shelve crée des fichiers qui gèrent un dictionnaire de données. La sauvegarde et la restauration de données sont triviales. Les complications éventuelles dépendent de votre code, de la quantité de données à rendre persistante et du degré d'intrication entre ces données.
Prenons un exemple simple, l'ébauche d'une classe Client et d'une classe Banque.
On doit pouvoir créer un nouveau client (compte de banque) et gérer les opérations de débit et de crédit. L'ébauche de la classe Banque à un dictionnaire clients qui contient l'état des comptes à l'instant T. Ce dictionnaire doit être restauré à l'ouverture du programme et sauvegardé avant la fin du programme.
La classe Client donne un ID unique à chaque client, pour cela il utilise la méthode count du module itertools. L'ID augmente de 1 à chaque création de clients. Mais il faut restaurer et sauvegarder son état à chaque fois que la Banque travaille sinon count reprend du début et génère des IDs qui existe déjà.
from itertools import count
class Client:
_ids = count(1)
def __init__(self, nom: str = '', prenom: str = ''):
self.__id = next(self._ids)
self.__nom = nom
self.__prenom = prenom
self.__solde = 0
@property
def id(self):
return self.__id
@property
def nom(self):
return self.__nom
@property
def prenom(self):
return self.__prenom
@property
def solde(self):
return self.__solde
def __repr__(self):
s = "< Client : id = {0.id} nom = {0.nom}, prénom = {0.prenom}, ".format(
self)
s += locale.currency(self.solde, symbol=True, grouping=True) + ">"
return s
__str__ = __repr__
def credit(self, montant: float = 0):
if montant > 0:
self.__solde += montant
def debit(self, montant: float = 0):
if montant > 0 and self.__solde > montant:
self.__solde -= montant
import shelve
# Le chemin du fichier dépend de votre environnement de travail
shelve_file_name = 'F:/test-python/Tests/blog/shelve_clients'
class Banque:
def __init__(self):
self.dict_clients = self.restore_clients()
def save_clients(self):
print("{:-^30s}".format("Fermeture de la banque"))
self.liste_clients()
with shelve.open(shelve_file_name, writeback=True) as dico:
dico['clients'] = self.dict_clients
dico['ids'] = Client._ids
def restore_clients(self):
print("{:-^30s}".format("Ouverture de la banque"))
dict_clients = {}
with shelve.open(shelve_file_name) as dico:
if 'clients' in dico:
dict_clients = dico['clients']
if 'ids' in dico:
Client._ids = dico['ids']
if len(dict_clients) == 0:
nom = "Hagnoul"
prenom = "Daniel"
obj = Client(nom, prenom)
obj.credit(10000.0)
dict_clients[obj.id] = obj
return dict_clients
def add_client(self, nom, prenom, solde):
obj = Client(nom, prenom)
obj.credit(solde)
if obj.id not in self.dict_clients:
self.dict_clients[obj.id] = obj
else:
raise ValueError("Erreur fatale, cette valeur d'id existe déjà")
def liste_clients(self):
for obj in self.dict_clients.values():
print(obj)
b = Banque()
b.liste_clients()
b.add_client("Lapoire", "Albertine", 7000)
b.dict_clients[1].debit(27.69)
b.save_clients()
b = Banque()
b.liste_clients()
b.add_client("Malautrou", "Pierre", 278.27)
b.dict_clients[2].debit(312.59)
b.save_clients()
b = Banque()
b.liste_clients()
b.dict_clients[1].credit(2157.00)
b.save_clients()
!jupyter nbconvert --to html shelve_banque.ipynb