Partage
  • Partager sur Facebook
  • Partager sur Twitter

Ajout dynamique de propriétés

Anonyme
    10 novembre 2011 à 19:04:13

    Bonjour,

    Je suis en train d'essayer d'ajouter dynamiquement des propriétés à une classe.
    Pour cela, j'ai définit une classe avec un constructeur prenant comme paramètre une liste de nom propriétés à mettre en place.
    Le constructeur appel la fonction setattr.

    Voici le code que j'ai écrit.
    # -*-coding:utf-8 -*
    
    class Table:
        def __init__(self,attributs):
            for attr in attributs:
                fget = lambda obj : obj._get_attr(attr)
                fset = lambda obj,val : obj._set_attr(attr,val)
                setattr(self.__class__,attr,property(fget,fset))
                
        def _get_attr(self,name):
            print("Acces à l'attribut "+name)
            
        def _set_attr(self,name,value):
            print("Set de l'attribut "+name+" avec la valeur "+str(value))
        
    if __name__ == "__main__":
        attributs=['id','name','comment']
        table=Table(attributs)
        print(dir(table))
        table.id=7
    


    Voici la sortie de ce bout de code:
    ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_get_attr', '_set_attr', 'comment', 'id', 'name']
    Set de l'attribut comment avec la valeur 7


    On voit donc que les attributs sont bien ajoutés.
    Lorsque j'affecte une valeur à un attribut la propriété fonction (la fonction est appelée) mais pas avec le bon nom.
    Dans l'exemple j'affecte 'id' mais la sortie indique l'attribut 'comment'
    Set de l'attribut comment avec la valeur 7


    Qu'es ce qui ne va pas dans mon code?
    Merci

    Edit : J'utilise Python3
    • Partager sur Facebook
    • Partager sur Twitter
      10 novembre 2011 à 20:13:54

      Bonsoir,

      Pas de solution, mais un code minimal qui reproduit le problème :

      fonctions = []
      for n in ['un','deux','trois']:
        f = lambda : n
        fonctions.append(f)
      
      for f in fonctions: print(f())
      


      trois
      trois
      trois


      Ça a donc à voir au foctionnement des lambda à priori; je continu les investigations en attendant les lumières d'un membre plus expérimenté.

      PS : ça ressemble pas mal aux namedtuple ce que tu cherches à faire non ?


      [edit]
      http://stackoverflow.com/questions/184 [...] ion-in-python

      ça fonctionne bien avec:
      fget = lambda obj, attr=attr : obj._get_attr(attr)
      fset = lambda obj,val, attr=attr : obj._set_attr(attr,val)
      
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        10 novembre 2011 à 20:57:05

        Merci :)
        En effet ça marche avec attr=attr. Je pensai que la variable attr été fermé dans la lambda.

        Je cherche à faire une sorte d'ORM de tables d'une base de données. C'est pourquoi j'essaye d'attribuer les propriétés dynamiquement en fonction d'un descripteur de table.

        Je ne connaissais pas les namedtuples, j'ai pas encore compris le principe mais j'ai vu que il utilisé ça pour avec des bases de données. Je vais creuser un peu dans la direction ;)
        • Partager sur Facebook
        • Partager sur Twitter
          10 novembre 2011 à 21:32:27

          Citation : devendart

          Je cherche à faire une sorte d'ORM de tables d'une base de données. C'est pourquoi j'essaye d'attribuer les propriétés dynamiquement en fonction d'un descripteur de table.


          Dans ce cas, mieux vaut regarder du coté des métaclasses plutôt que de faire du monkey patching à tout va : http://stackoverflow.com/questions/100 [...] 81949#6581949
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            10 novembre 2011 à 22:16:44

            Je me suis renseigné sur les métaclasses mais je ne suis pas arrivé à me passer de la fonction setattr.
            Le code que je vous est montré n'est pas le code final.
            Je suis parti sur l'utilisation de la fonction type de cette manière.
            # -*-coding:utf-8 -*
            
            class Table:
                def __init__(self):
                    for attr in self.attributs:
                        fget = lambda obj,attr=attr : obj._get_attr(attr)
                        fset = lambda obj,val,attr=attr : obj._set_attr(attr,val)
                        setattr(self.__class__,attr,property(fget,fset))
            
                def _get_attr(self,name):
                    print("Accès à l'attribut "+name)
            
                def _set_attr(self,name,value):
                    print("Set de l'attribut "+name+" avec la valeur "+str(value))
                    
            def createTable(tableName,attributs):
                classTable=type(tableName,(Table,),{'attributs':attributs})
                return classTable()
                
            if __name__ == "__main__":
                attributs=['id','name','comment']
                t=createTable('Cells',attributs)
                t.id=6
            

            Qui donne bien le résultat voulu avec la possibilité de créer plusieurs tables différentes sans que les attributs ne se retrouve dans tout les objets.

            Existe-t-il une meilleur solution? en utilisant une metaclass autrement?

            Merci
            • Partager sur Facebook
            • Partager sur Twitter
              10 novembre 2011 à 23:58:11

              Dans ce bout de code, je ne pense pas que la classe Table soit utile. En fait, en coulisse, settattr() ne fait que rajouter des entrées dans le dictionnaire que tu passes à type() en troisième argument; tu peux donc faire tout directement dans createTable() en préparant le dictionnaire avant de l'envoyer à type() ;) (sans classe de base donc)
              • Partager sur Facebook
              • Partager sur Twitter

              Ajout dynamique de propriétés

              × 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