[vaguement résolu] surcharger __getattribute__

surcharger __getattribute__ [vaguement résolu] - Python - Programmation

Marsh Posté le 19-09-2006 à 21:48:33    

Bon, pour ne pas mourir idiot, j'aimerais savoir ce que vous pensez de mon idée de départ et de la manière dont je l'ai implémentée.
 
J'ai une classe C avec de nombreux attributs (des entiers et des fonctions). Pour ce qui est des entiers, j'aimerais pouvoir vérifier automatiquement comment les affectations se font (du genre, interdit d'entrer des valeurs trop grandes). Pour plus de souplesse, je mets mes attributs dans un dictionnaire et j'en contrôle l'accès à l'aide de __getattribute__ / __setattr__ :
 

Code :
  1. class C(dict):
  2.     def __init__(self):
  3.         # les valeurs par défaut :
  4.         self["v1"] = 0
  5.         self["v2"] = 0
  6.        
  7.     def __setattr__(self, name, value):
  8.         if name in self:
  9.             self[name][0] = value
  10.            # ... et j'ajoute ici une vérification sur "value"
  11.         else:
  12.             raise # exception pour signaler qu'on tente de modifier un attribut qui n'existe pas.
  13.     def __getattribute__(self, name):
  14.             if name in self:
  15.                 return self[name]  # je retourne la valeur demandée.
  16.             else:
  17.                 raise # exception pour signaler qu'on tente d'accéder à un attribut qui n'existe pas.
  18.     def foo:
  19.         pass # je coupe : code sans intérêt


Ca fonctionne; mais __getattribute__ intercepte aussi les appels de fonction, par exemple :

Code :
  1. c = C()
  2. c.foo()


... et j'ai droit à un message d'erreur (le raise dans __getattribute__), puisque mon c.__getattribute__ récupère un "foo" en argument et que "foo" n'existe pas dans le dictionnaire. Comment réécrire __getattribute__ de manière à ne pas torpiller les appels aux fonctions de C ?
 
Si vous pouviez me dire ce que vous en pensez... Merci !
 
edit : correction du nom de la fonction dans ma classe.


Message édité par suizokukan le 19-09-2006 à 22:57:03

---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 21:48:33   

Reply

Marsh Posté le 19-09-2006 à 22:14:25    

Et si tu utilisais des property plutôt ?
 
Si j'ai bien compris ton truc, ça correspond exactement à ce que tu veux faire : http://www.python.org/download/rel [...] /#property

Reply

Marsh Posté le 19-09-2006 à 22:18:25    

> multani : merci du coup de main. Je connais les properties mais je ne les utilise pas volontairement. En effet, pour chaque attribut tu dois créer une property. Or je voudrais créer un seul couple de fonctions [get/set] pour vérifier l'accès à toutes les variables de ma classe. Un peu comme s'il existait un property pour un ensemble de variables.


---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 22:34:23    

Tu peux toujours essayer de récupérer par reflexion (avec getattr) une référence vers la méthode, si la clé n'est pas dans le dictionnaire. Mais tu risques d'être coincer au niveau des arguments à passer à la méthode après (je passe la main pour ça).
 
Sinon, ce serait pas plus simple de faire deux fonctions get/set, qui prennent en premier argument le nom de ton attribut ?

Reply

Marsh Posté le 19-09-2006 à 22:42:45    

> multani : pour ta deuxième idée, ce serait "plus simple", mais moins élégant. Et ma petite (:)) expérience me prouve qu'il ne faut jamais négliger la simplicité dans la lecture du code d'un projet. D'autant que le mien s'annonce long et difficile (pour moi !)
 
Je me débats donc avec ta première remarque et je cherche toujours un exemple qui me serait accessible d' overriding de la fonction __getattribute__... Et moi, je ne peux pas passer la main. :D  
 
Merci de ton aide.


---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 22:56:18    

Bon, je crois y être arrivé, mais quel merd*** ! Y va falloir que je relise de la doc...
 

Code :
  1. class C(dict):
  2.     def __init__(self):
  3.         dict.__setitem__( self, "v1", 0 )
  4.         dict.__setitem__( self, "v2", 0 )
  5.         self.foo()
  6.     def __setattr__(self, name, value):
  7.         if name in self:
  8.             self[name] = value
  9.         else:
  10.             raise
  11.     def __getattr__(self, name):
  12.         if name in self:
  13.             return dict.__getitem__(self, name)
  14.         else:
  15.             raise
  16.     def foo(self):
  17.         pass


En fait, __getattr__ n'a pas l'air d'intercepter les appels de fonction ... ?!?!
 
Donc voici le comportement attendu (et effectif) de cette classe :

Code :
  1. c = C()
  2. c.v1 = 3 # ok, on passe par __setattr__
  3. print c.v2 # ok, on passe par __getattribute__
  4. c.foo() # ok (donc pas d'interception par __getattribute__)
  5. c.v5 = 0 # raise déclenché par __setattr__
  6. print c.v6 # raise déclenché par __getattribute__


---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 22:59:34    

En fait, je vois pas. On peut pas utiliser getattr dans __getattribute__, sinon, on se mange un "RuntimeError: maximum recursion depth exceeded", donc c'est ratal [:petrus75]

Reply

Marsh Posté le 19-09-2006 à 23:03:13    

> multani : et pour clore (?) ce débat, est-ce que tu verrais une autre manière de résoudre le problème initial ? Peut-être est-ce ma classe qui est mal fichue. Sur des détails de conception comme celui-ci, je manque beaucoup d'expérience.
 
Merci pour ton coup de main.


---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 23:07:13    

avec getattribute, il faut tout faire au niveau de la résolution. y compris déléguer à la classe parente.

Reply

Marsh Posté le 19-09-2006 à 23:10:01    

> Taz, c'est vraiment un sujet difficile pour moi, mais je tente de m'accrocher. Pourrais-tu me donner quelques explications ? Ou un bout de code ?


---------------
rule #1 : trust the python
Reply

Marsh Posté le 19-09-2006 à 23:10:01   

Reply

Marsh Posté le 19-09-2006 à 23:10:58    

Là, du coup, je vois pas trop l'intérêt d'hériter de dict ...

Reply

Marsh Posté le 21-09-2006 à 15:42:38    

Citation :

En effet, pour chaque attribut tu dois créer une property. Or je voudrais créer un seul couple de fonctions [get/set] pour vérifier l'accès à toutes les variables de ma classe. Un peu comme s'il existait un property pour un ensemble de variables.


Résultat tu t'emmerdes et tu fais des trucs crades [:petrus75]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed