#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Author: freezed 2018-01-25 Version: 0.1 Licence: `GNU GPL v3`: http://www.gnu.org/licenses/ """ class DictionnaireOrdonne: """ Dictionnaire ordonne ==================== Notre dictionnaire ordonné. L'ordre des données est maintenu et il peut donc, contrairement aux dictionnaires usuels, être trié ou voir l'ordre de ses données inversées :Example: >>> fruits = DictionnaireOrdonne() >>> fruits {} >>> fruits["pomme"] = 52 >>> fruits["poire"] = 34 >>> fruits["prune"] = 128 >>> fruits["melon"] = 15 >>> fruits {'pomme': 52, 'poire': 34, 'prune': 128, 'melon': 15} >>> fruits.sort() >>> print(fruits) {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128} >>> legumes = DictionnaireOrdonne(carotte = 26, haricot = 48) # Test possible seulement avec python 3.6, # voir: www.python.org/dev/peps/pep-0468/ #>>> print(legumes) #{'carotte': 26, 'haricot': 48} >>> len(legumes) 2 >>> legumes.reverse() >>> fruits = fruits + legumes >>> fruits {'melon': 15, 'poire': 34, 'pomme': 52, 'prune': 128, 'haricot': 48, 'carotte': 26} >>> del fruits['haricot'] >>> 'haricot' in fruits False >>> 'pomme' in fruits True >>> legumes['haricot'] 48 >>> for cle in legumes: ... print(cle) ... haricot carotte >>> fruits.keys() ['melon', 'poire', 'pomme', 'prune', 'carotte'] >>> legumes.keys() ['haricot', 'carotte'] >>> fruits.values() [15, 34, 52, 128, 26] >>> legumes.values() [48, 26] >>> for nom, qtt in legumes.items(): ... print("{0} ({1})".format(nom, qtt)) ... haricot (48) carotte (26) >>> mots = {'olive': 51, 'identite': 43, 'mercredi': 25, 'prout': 218, 'assiette': 8, 'truc': 26} >>> mots_ordonne = DictionnaireOrdonne(mots) >>> mots_ordonne.sort() >>> mots_ordonne {'assiette': 8, 'identite': 43, 'mercredi': 25, 'olive': 51, 'prout': 218, 'truc': 26} """ def __init__(self, base={}, **donnees): """Constructeur de notre objet. Il peut ne prendre aucun paramètre (dans ce cas, le dictionnaire sera vide) ou construire un dictionnaire remplis grâce : - au dictionnaire 'base' passé en premier paramètre ; - aux valeurs que l'on retrouve dans 'donnees'.""" self._cles = [] # Liste contenant nos clés self._valeurs = [] # Liste contenant les valeurs correspondant à nos clés # On vérifie que 'base' est un dictionnaire exploitable if type(base) not in (dict, DictionnaireOrdonne): raise TypeError( \ "le type attendu est un dictionnaire (usuel ou ordonne)") # On récupère les données de 'base' for cle in base: self[cle] = base[cle] # On récupère les données de 'donnees' for cle in donnees: self[cle] = donnees[cle] def __repr__(self): """Représentation de notre objet. C'est cette chaîne qui sera affichée quand on saisit directement le dictionnaire dans l'interpréteur, ou en utilisant la fonction 'repr'""" chaine = "{" premier_passage = True for cle, valeur in self.items(): if not premier_passage: chaine += ", " # On ajoute la virgule comme séparateur else: premier_passage = False chaine += repr(cle) + ": " + repr(valeur) chaine += "}" return chaine def __str__(self): """Fonction appelée quand on souhaite afficher le dictionnaire grâce à la fonction 'print' ou le convertir en chaîne grâce au constructeur 'str'. On redirige sur __repr__""" return repr(self) def __len__(self): """Renvoie la taille du dictionnaire""" return len(self._cles) def __contains__(self, cle): """Renvoie True si la clé est dans la liste des clés, False sinon""" return cle in self._cles def __getitem__(self, cle): """Renvoie la valeur correspondant à la clé si elle existe, lève une exception KeyError sinon""" if cle not in self._cles: raise KeyError( \ "La clé {0} ne se trouve pas dans le dictionnaire".format( \ cle)) else: indice = self._cles.index(cle) return self._valeurs[indice] def __setitem__(self, cle, valeur): """Méthode spéciale appelée quand on cherche à modifier une clé présente dans le dictionnaire. Si la clé n'est pas présente, on l'ajoute à la fin du dictionnaire""" if cle in self._cles: indice = self._cles.index(cle) self._valeurs[indice] = valeur else: self._cles.append(cle) self._valeurs.append(valeur) def __delitem__(self, cle): """Méthode appelée quand on souhaite supprimer une clé""" if cle not in self._cles: raise KeyError( \ "La clé {0} ne se trouve pas dans le dictionnaire".format( \ cle)) else: indice = self._cles.index(cle) del self._cles[indice] del self._valeurs[indice] def __iter__(self): """Méthode de parcours de l'objet. On renvoie l'itérateur des clés""" return iter(self._cles) def __add__(self, autre_objet): """On renvoie un nouveau dictionnaire contenant les deux dictionnaires mis bout à bout (d'abord self puis autre_objet)""" if type(autre_objet) is not type(self): raise TypeError( \ "Impossible de concaténer {0} et {1}".format( \ type(self), type(autre_objet))) else: nouveau = DictionnaireOrdonne() # On commence par copier self dans le dictionnaire for cle, valeur in self.items(): nouveau[cle] = valeur # On copie ensuite autre_objet for cle, valeur in autre_objet.items(): nouveau[cle] = valeur return nouveau def items(self): """Renvoie un générateur contenant les couples (cle, valeur)""" for i, cle in enumerate(self._cles): valeur = self._valeurs[i] yield (cle, valeur) def keys(self): """Cette méthode renvoie la liste des clés""" return list(self._cles) def values(self): """Cette méthode renvoie la liste des valeurs""" return list(self._valeurs) def reverse(self): """Inversion du dictionnaire""" # On crée deux listes vides qui contiendront le nouvel ordre des clés # et valeurs cles = [] valeurs = [] for cle, valeur in self.items(): # On ajoute les clés et valeurs au début de la liste cles.insert(0, cle) valeurs.insert(0, valeur) # On met ensuite à jour nos listes self._cles = cles self._valeurs = valeurs def sort(self): """Méthode permettant de trier le dictionnaire en fonction de ses clés""" # On trie les clés cles_triees = sorted(self._cles) # On crée une liste de valeurs, encore vide valeurs = [] # On parcourt ensuite la liste des clés triées for cle in cles_triees: valeur = self[cle] valeurs.append(valeur) # Enfin, on met à jour notre liste de clés et de valeurs self._cles = cles_triees self._valeurs = valeurs if __name__ == "__main__": """ Active les doctests """ import doctest doctest.testmod()