Bonjour !
Voilà, je tente quelque chose, mais je suis pas certain que je m’y prend de la bonne manière, donc je viens demander des avis. Pour la faire courte, je travaille sur une petite librairie perso permettant d’extraire des résultats de fichier log de différents programmes (de chimie quantique, mais osef). Évidement, chaque programme crache ses résultats sous une forme différente, même si il y a certaines résultats communs, et d’autres qui sont spécifiques à un programme donné.
Plutôt que de définir, pour chaque type de fichier, des fonctions get_machin()
, je me suis dit que j’allais tenter une approche un peu différente (et qui a le chic de permettre de définir des choses à postériori), c’est de pouvoir, à n’importe quel moment de l’exécution:
1 2 3 4 5 6 7 8 9 10 | @define_property(FichierLogDuProgrammeTruc, 'propriétéBidule'): def get_propriete_bidule(obj): truc = obj.faire_machin() # "obj" est une instance de FichierLogDuProgrammeTruc # ... aller chercher l'info, # la transformer dans le bon format, # éventuellement faire un calcul ou deux ... return bidule f = FichierLogDuProgrammeTruc() f.get_property('propriétéBidule') |
Évidement, propriétéBidule
peut très bien se retrouver dans différents types de fichier (ou pas), donc il faut que je puisse définir une fonction par type de fichier. J’ai donc testé de mon coté, et je me retrouve avec le POC suivant:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | class File: properties = {} def __init__(self): pass @classmethod def define_property(cls, property, f): if cls not in cls.properties: cls.properties[cls] = {} cls.properties[cls][property] = f def get_property(self, property): if type(self) in self.properties: if property in self.properties[type(self)]: return self.properties[type(self)][property](self) else: raise Exception('no {}'.format(property)) else: raise Exception('not class') class FileA(File): def __init__(self): super().__init__() self.a = 'a' self.c = 'c' class FileB(File): def __init__(self): super().__init__() self.b = 'b' self.c = 'c' def define_propery(cls, property): def wrapper(f): cls.define_property(property, f) return wrapper @define_propery(FileA, 'a') def get_a(obj): return obj.a + ' in A' @define_propery(FileA, 'c') def get_c(obj): return obj.c + ' in A' @define_propery(FileB, 'b') def get_b(obj): return obj.b + ' in B' @define_propery(FileB, 'c') def get_c(obj): return obj.c + ' in B' obj_a = FileA() print(obj_a.get_property('a')) print(obj_a.get_property('c')) obj_b = FileB() print(obj_b.get_property('b')) print(obj_b.get_property('c')) print(obj_b.get_property('a')) # ça crache! |
Ça fait le café, puisqu’on a bien c
qui est défini deux fois sans problème et le programme qui se casse la gueule quand on demande a
pour FileB
(dernière ligne):
1 2 3 4 5 6 7 8 9 10 | a in A c in A b in B c in B Traceback (most recent call last): File "/home/pbeaujea/Devels/scripts/test.py", line 72, in <module> print(obj_b.get_property('a')) File "/home/pbeaujea/Devels/scripts/test.py", line 19, in get_property raise Exception('no {}'.format(property)) Exception: no a |
… mais je suis pas spécialement heureux: déjà, le dictionnaire est copié à la création de tout objet, ce qui est un peu idiot. Ensuite, et c’est lié, il y a un certain bordel qui provient du fait qu’un dictionnaire est immutable (immuable?), ce qui fait qu’on est obligé de définir self.properties[cls]
, sans quoi on ne peut pas (re)définir une propriété unique à chaque classe.
Une solution serait par exemple de passer par une variable globale pour properties
, mais je suis moyennement chaud aussi, parce que c’est toujours un peu pénible avec les import
après.
Donc, si vous avez une idée plus intelligente, j’en serais fort heureux !
D’avance merci