Partage
  • Partager sur Facebook
  • Partager sur Twitter

Encapsulation et propriété

Sujet résolu
    9 août 2010 à 13:12:41

    J'ai vu que il y a peu, le tutoriel python a été agrémenté de quelques chapitres sur la POO coté développeur, et le second chapitre parle des propriétés. En fait j'aimerais savoir l'utilité des propriété par rapport aux méthodes spéciales ? En effet je ne vois pas pourquoi les utiliser, sachant qu'elle ne sont pas 'parfaite' :
    class Test(object):
    	def __init__(self,a):
    		self._a = a
    	def _get_a(self):
    		return self._a
    	def _set_a(self,val):
    		if val < 0:
    			val = 0
    		self._a = 0
    	a = property(_get_a,_set_a)
    
    c = Test(-15)
    # ici c.a vaut -15
    # de plus je peux 'tricher' en faisant c._a = -18 et c.a vaudra -18 (au lieu de 0)
    

    J'ai cherché dans le manuel de référence python mais je n'ai pas trouvé grand chose dessus en fait, c'est pour ça que je pose la question ! (Le seul passage que j'ai vu dit "The property() function is implemented as a data descriptor. Accordingly, instances cannot override the behavior of property.")
    • Partager sur Facebook
    • Partager sur Twitter
      9 août 2010 à 13:52:27

      # ici c.a vaut -15
      

      Rien à voir avec les propriétés, là, mais plus avec le manque de contrôle dans le constructeur.

      # de plus je peux 'tricher' en faisant c._a = -18 et c.a vaudra -18 (au lieu de 0)
      

      Si tu doubles l'underscore devant l'attribut (__a ), il devient beaucoup plus compliqué de "tricher" (à cause du name mangling).
      • Partager sur Facebook
      • Partager sur Twitter
      Zeste de Savoir, le site qui en a dans le citron !
        9 août 2010 à 14:01:14

        Citation : NoHaR

        # ici c.a vaut -15
        


        Rien à voir avec les propriétés, là, mais plus avec le manque de contrôle dans le constructeur.


        Certes, mais bon avec les méthodes spéciales le problème aurait été réglé :)

        Citation


        # de plus je peux 'tricher' en faisant c._a = -18 et c.a vaudra -18 (au lieu de 0)
        


        Si tu doubles l'underscore devant l'attribut (__a ), il devient beaucoup plus compliqué de "tricher" (à cause du name mangling).


        Oui je connaissais pas le 'name mangling', mais reste que je peux tout de même accéder à l'attribute ? (bon ok il faut s'amuser avec les noms de variables mais certes).
        En fait je ne voulais pas du tout dire que les propriétés sont inutiles (enfin je me suis quand même mal exprimé en relisant mon post :p ), mais plutôt quelle sont leurs avantages par rapports aux méthodes spéciales ? (__getattribute__, __getattr__, __setattr__, __delattr__ ) J'ai tout simplement commencer à prendre l'habitude d'utiliser ces méthodes pour mes classes (pour le peu que je fais de POO :p ), et donc j'aimerais savoir si c'était une mauvaise habitude ? Ou si les deux étaient équivalente (d'un point de vue encapsulation) ?
        • Partager sur Facebook
        • Partager sur Twitter
          9 août 2010 à 14:33:31

          Pour ce qui est de la gestion des attributs, les propriétés permettent une gestion plus fine que les méthodes __getattr__, etc. : tu peux facilement implémenter des contrôles différents selon les attributs auxquels tu cherches à accéder.

          Pour le reste, elles permettent aussi d'interdire facilement l'accès "en écriture" sur un attribut (il suffit de ne pas spécifier de setter pour une propriété donnée). Elles permettent aussi de créer des pseudo-attributs qui n'ont pas forcément de réelle existence (en mémoire, je veux dire) dans la classe : par exemple, je peux créer une propriété 'aire' sur une classe Rectangle , seulement accessible par son getter (return self.__hauteur * self.__largeur ), sans avoir à créer d'attribut __aire. L'intérêt de cette propriété est surtout qu'elle allège la syntaxe, et rend la classe plus intuitive à utiliser en Python.
          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
            9 août 2010 à 14:51:34

            Citation : NoHaR

            Pour ce qui est de la gestion des attributs, les propriétés permettent une gestion plus fine que les méthodes __getattr__, etc. : tu peux facilement implémenter des contrôles différents selon les attributs auxquels tu cherches à accéder.

            Pour le reste, elles permettent aussi d'interdire facilement l'accès "en écriture" sur un attribut (il suffit de ne pas spécifier de setter pour une propriété donnée). Elles permettent aussi de créer des pseudo-attributs qui n'ont pas forcément de réelle existence (en mémoire, je veux dire) dans la classe : par exemple, je peux créer une propriété 'aire' sur une classe Rectangle , seulement accessible par son getter (return self.__hauteur * self.__largeur ), sans avoir à créer d'attribut __aire. L'intérêt de cette propriété est surtout qu'elle allège la syntaxe, et rend la classe plus intuitive à utiliser en Python.


            Tout ça on peut le faire avec les méthodes spéciales non ?
            Par exemple :
            class Rect(object):
                def __init__(self,larg,haut,x): # x variable inutile
                    self.l, self.h, self.x = larg, haut, x
                def __getattribute__(self,name):
                    return object.__getattribute__(self,name)
                def __getattr__(self,name):
                    if name == 'aire':
                        return self.l * self.h
                def __setattr__(self,name, val):
                    if name == 'l' or name == 'h':
                        if val < 0:
                            val = 0
                    elif name == 'x':
                        if type(val) != type(''):
                            val = ''
                    else:
                        print('Attribut immutable !')
                        return
                    object.__setattr__(self,name,val)
            
            >>> c = Rect(12,18,0)
            >>> c.l,c.h,c.x
            (12, 18, '')
            >>> c.aire
            216
            >>> c.h = -48
            >>> c.h, c.aire
            (0,0)
            

            Bon là j'y ai été un peu brutalement (si l'argument n'est pas correctement, on met un argument par défaut), mais j'aurais très bien pu faire autre chose (enfin je pense que tu t'en doutes :p ).
            Après je dois avoué que pour l'attribut aire cela oblige a créé un cas spécial dans __setattribute__, mais vu qu'il n'a besoin d'être créé qu'une fois pour tous les 'pseudo-attributs' !
            Si ce n'est pas de ça que tu parlais dans ton post, mea-culpa pour ce post idiot ^^
            • Partager sur Facebook
            • Partager sur Twitter
              10 août 2010 à 11:15:25

              Je suis d'accord, tu peux faire tout ça en utilisant les méthodes spéciales, mais tu perds en lisibilité en collant un branchement conditionnel.
              Si ta classe doit avoir une dizaine de pseudo-attributs différents (prends par exemple la classe Rect de Pygame qui permet d'influencer sa taille/position en jouant sur les coordonnées des points "topleft", "bottomright", "center" ou plus indépendamment les coordonnées "top", "left", "bottom", "right", "x", "y", "centerx", "centery" et les valeurs "area", "size" (c'est une paire), "width", "height"), tes branchements conditionnels deviennent énormes, et beaucoup moins faciles à maintenir.
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                10 août 2010 à 11:27:12

                Citation : NoHaR

                Je suis d'accord, tu peux faire tout ça en utilisant les méthodes spéciales, mais tu perds en lisibilité en collant un branchement conditionnel.
                Si ta classe doit avoir une dizaine de pseudo-attributs différents (prends par exemple la classe Rect de Pygame qui permet d'influencer sa taille/position en jouant sur les coordonnées des points "topleft", "bottomright", "center" ou plus indépendamment les coordonnées "top", "left", "bottom", "right", "x", "y", "centerx", "centery" et les valeurs "area", "size" (c'est une paire), "width", "height"), tes branchements conditionnels deviennent énormes, et beaucoup moins faciles à maintenir.


                Je vois ce que tu veux dire mais avec les propriétés cela m'oblige à créer autant de fonction (en double), est ce vraiment plus lisible ? (Je n'ai pas vraiment utilisé les propriétés, mais je trouves que avoir un grand nombre de fonction pour n'est pas forcément plus lisible qu'un grand branchement conditionnel (dans ce cas précis je parle)) De plus je peux gérer 2 attributs de la même façon (dans mon exemple l et h), est ce que on peut le faire avec les propriétés ? Enfin bon je vois déjà un peu mieux quel peut être l'utilité des propriétés, merci à toi, je pense que j'utiliserais l'un ou l'autre en fonction :)
                • Partager sur Facebook
                • Partager sur Twitter
                  10 août 2010 à 12:23:59

                  Citation : Holt


                  Je vois ce que tu veux dire mais avec les propriétés cela m'oblige à créer autant de fonction (en double), est ce vraiment plus lisible ?


                  Personnellement je préfère avoir plusieurs petites méthodes plutôt qu'une seule, grosse : c'est beaucoup plus facile à gérer si tu dois dériver ta classe, par exemple.

                  Citation : Holt


                  De plus je peux gérer 2 attributs de la même façon (dans mon exemple l et h), est ce que on peut le faire avec les propriétés ?


                  Non, en effet.

                  Citation : Holt


                  Enfin bon je vois déjà un peu mieux quel peut être l'utilité des propriétés, merci à toi, je pense que j'utiliserais l'un ou l'autre en fonction :)


                  Oui, ça dépend avant tout de ce à quoi est destinée ta classe.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !

                  Encapsulation et propriété

                  × 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