Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comportement variable de __getattr__

Sujet résolu
    14 septembre 2020 à 18:27:41

    Bonjour,
    j'ai constaté sans pouvoir l'expliquer un comportement différent quand on surcharge __getattr__ en même temps que __setattr__ ou pas.


    Dans une classe ou je met les deux, le __getattr__ est appelé que l'attribut existe ou pas, alors que dans une classe ou je ne met que le __getattr__, il n'est appelé que si l'attribut n'existe pas (ce qui est il me semble le comportement attendu).

    Comment se fait-il que le __getattr__ soit appelé même quand l'attribut existe à partir du moment ou __setattr__ est également défini ?

    class TestA: 
        def __init__(self): 
            self.a = 1 
            self.b = 2 
            self.C = 3 
    
        def __getattr__(self, nom): 
            print(f"__getattr__ {nom}") 
    
        def __setattr__(self, nom, valeur): 
            print(f"__setattr__ {nom} {valeur}")
    
    class TestB: 
        def __init__(self): 
            self.a = 1 
            self.b = 2 
            self.C = 3 
    
        def __getattr__(self, nom): 
            print(f"__getattr__ {nom}") 

    >>> tA = TestA()                                                            
    __setattr__ a 1
    __setattr__ b 2
    __setattr__ C 3
    
    >>> tB = TestB()                                                            
    
    >>> tA.a                                                                    
    __getattr__ a
    
    >>> tB.a                                                                    
    1
    
    >>> tA.z                                                                    
    __getattr__ z
    
    >>> tB.z                                                                    
    __getattr__ z

     J'ai fais le test sous Python 2.7.17 et Python 3.6.9 avec le même résultat.

    -
    Edité par Emmanuel Letremble 14 septembre 2020 à 18:32:36

    • Partager sur Facebook
    • Partager sur Twitter
      15 septembre 2020 à 23:34:00

      Bonsoir,

      Alors, la méthode __getattr__ n'est effectivement appelée seulement si la méthode __getattributes__ n'aboutit pas, et c'est le cas si elle ne trouve pas l'attribut recherché parmi ceux de l'objet.

      Quand tu redéfinis ta fonction __setattr__, le comportement d'affectation d'attribut est changé pour ton objet, et comme ici tu ne fais seulement qu'un print, les attributs de l'__init__ n'existent pas vraiment dans l'objet (print n'a effectivement pas ça pour effet). D'ailleurs, si après l'instanciation de TestA, tu fais tA.__dict__ tu pourras observer que tA ne possède effectivement aucun attribut. Par conséquent, la méthode __getattributes__ rate, et __getattr__ est appelée.

      Pour corriger cela, il faut rendre à __setattr__ son comportement par défaut en ajoutant après ton print :

      object.__setattr__(self, nom, valeur)

      Avec un __setattr__ fonctionnel, les attributs existent bel et bien, et la fonction __getattr__ ne devrait plus être appelée.

      En espérant t'avoir aidé,

      Bonne soirée :)

      -
      Edité par WexyR 15 septembre 2020 à 23:36:07

      • Partager sur Facebook
      • Partager sur Twitter
      Si je suis tête en l'air, c'est par habitude de viser le sommet
        16 septembre 2020 à 0:01:30

        En effet dit comme ça c'est beaucoup plus clair !
        Je comprend à présent parfaitement pourquoi ça réagit de cette façon.

        J'étais complètement passé à coté du fait que __init__ appelait __setattr__ pour initialiser les attributs.

        Mille mercis

        -
        Edité par Emmanuel Letremble 16 septembre 2020 à 0:03:40

        • Partager sur Facebook
        • Partager sur Twitter

        Comportement variable de __getattr__

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown