IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

class, instance, attribut, propriété et compagnie


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Points : 16
    Points
    16
    Par défaut class, instance, attribut, propriété et compagnie
    bonjour à tous,

    j'essaye désespérément de me créer ma propre ORM
    avec la possibilité de vérifier ou transformer le type de la valeur passée

    pour cela, je me suis tourné d'abord vers les attributs

    en redéfinissant le __setattr__ et le __getattr__
    j'arrive à m'en sortir

    mais du coup, je ne peux plus instancier mon objet :

    class utilisateur(object):
    nom= "default"
    ...........


    user1 =utilisateur()
    user2 =utilisateur()
    user1.nom = "nouveau"
    print user2.nom -> me retourne "nouveau"

    premier arrachage de cheveux, mais j'ai compris que j'avais crée une variable pour ma classe, donc commune à toute mes instances

    j'ai le même problème avec les property et les fget, fset, fdel

    et impossible de le faire avec une instance

    pourtant , quand je regarde la doc d'une ORM comme elixir

    class utilisateur(Entity):
    nom = Field (je sais plus trop la syntax )

    je peux bien instancier utilisateur sans aucun probléme, et quand j'assigne une valeur à nom, il reste toujours en type Field et nom en type String

    j'ai bien essayé de décortiquer le code d'Elixir, mais Entity dérive de Property qui dérive de ... qui dérive de .....................
    deuxieme arrachage de cheveux

    donc je suis preneur si quelqu'un peux me donner une piste pour résoudre mon problème
    ou du moins qui a un peu pitié de mon cuir chevelu

    merci de votre aide, bon weekend

    Kermit

    [edit]:
    j'ai oublié de precier
    j'ai essayé une autre méthode :
    retourné la valeur dans un dictionnaire "d'instance", qui contient les mêmes key que mes attributs, dans le __getattr__
    mais la, le __getattr__ s'appelle en boucle jusqu'à qu'une erreur soit levée

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonsoir,

    Je ne suis pas sûr d'avoir compris ce que tu veux faire, mais si tu préfixes le nom de variable par self (c'est à dire "self.nom=..." au lieu de "nom=..."), tu crées une variable propre à chacune des instances de la classe.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Salut.

    J'ai un peu de code, en vrac, qui pourrait peut-être t'éclaircir la voie

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    In [9]: class Property:
       ...:     def __init__(self, name, type):
       ...:         self.__name = name
       ...:         self.__type = type
       ...:
       ...:     @property
       ...:     def name(self):
       ...:         return self.__name
       ...:
       ...:     @property
       ...:     def type(self):
       ...:         return self.__type
       ...:
       ...:
     
    In [10]: class Model:
       ....:     name = Property("name", "varchar(255)")
       ....:     role = Property("role", "varchar(50)")
       ....:     id   = Property("id", "integer")
       ....:
       ....:
     
    In [11]: dir(Model)
    Out[11]: ['__doc__', '__module__', 'id', 'name', 'role']
     
    In [12]: Model.name
    Out[12]: <__main__.Property instance at 0x02DCEBE8>
     
    In [13]: Model.name.name
    Out[13]: 'name'
     
    In [14]: Model.name.type
    Out[14]: 'varchar(255)'
     
    In [15]: Model.id.type
    Out[15]: 'integer'
     
    In [16]: object = Model()
     
    In [17]: object.name = "Antoine"
     
    In [18]: object.role = "Developer"
     
    In [19]: object.id = 1
     
    In [20]: Model.name
    Out[20]: <__main__.Property instance at 0x02DCEBE8>
     
    In [21]: object.name
    Out[21]: 'Antoine'

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    bonsoir,

    @tyrtamos
    je suis d'accord avec toi pour le self.nom
    mais du coup, je n'ai pas le moyen de controller ce que je mets dedans

    @Antoine_935
    que dire ....... merci bcp
    ton code est simple et limpide, et réponds exactement à ce que je veux
    j'avais pourtant tourné les attribut, property et leurs accesseurs dans tout les sens, mais pas dans celui la, il faut croire

    encore merci pour la reponse et la réactivité

    Kermit

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    Bonjour,

    suite a un petit retour de mail avec Antoine, je reviens dessus, car je suis allé un peu vite sur le bouton "Résolu"

    on est d'accord que je veux reprendre le principe d'un orm, je ne peux pas réutilisé un existant car mes données ne viennent pas forcement d'une base sql.

    Mon but :
    - pouvoir "typé" une variable d'instance
    - faire d'autre manip a l'assignation, comme la MAJ de mon affichage

    le code qui se rapproche le plus de ce que je veux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    class field(object):
        def __init__(self):
            self._val = None
     
        def get(*args):
            self = args[0]
            return self._val
     
        def set(*args):
            self = args[0]
            value = args[-1]
            #LA, je suis heureux, car je peux faire mon cast, mon affichage, etc...
            self._val = value  
     
        val = property(fget=get, fset=set, doc='value of field')
     
    class Model(object):
        def __init__(self):
            f=field()
            setattr(self.__class__,  "name",property(fget=f.get,  fset=f.set) )
     
     
     
    mod1= Model()
    mod2= Model()
    mod1.name = "toto"
    print mod2.name
    ..........."toto"
    j'ai bien compris que name devient un attribut de class, donc je modifie mod1.name, je modifie l'attribut de class de Model, donc également de mod2

    je voudrais avoir la même, mais pour une variable d'instance
    La proposition d'Antoine me paraissait alléchante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    class field:
        def __init__(self, name, type):
            self.__name = name
            self.__type = type
     
        @property
        def name(self):
            return self.__name
     
        @property
        def type(self):
            return self.__type
     
     
     
    class Model:
            name = field("name", "varchar(255)")
     
    mod1= Model()
    mod2= Model()
    mod1.name = "toto"
    mod2.name = "titi"
    print mod1.name
    ....'toto'
    print mod2.name
    ....'titi'
    print type(mod1.name)
    ...<type 'str'>
    ici j'ai bien des valeurs d'instance
    mais quand j'assigne une chaine à ma variable name, cela "écrase" mon type field

    je voudrais éviter de passer par des fonction setName, getName, car avec bcp de champ, cela va être lourd à la déclaration.

    dans l'utilisation du code aussi, autant à l écriture que pour sa compréhension

    societe.adresse me retourne une chaine
    societe.adresse.ville me retourne la ville

    plus sexy que
    societe.getAdresse().getString()
    societe.getAdresse().getVille().getString()

    peut être que j'essaye de faire quelque chose d'impossible en python, pourtant, je reviens sur l'exemple d'Elixir de mon premier poste, qui fonctionne bien

    merci pour votre attention, j'espere que sur le cout, j'ai été clair

    Kermit

  6. #6
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Ce que tu fais est un peu trop compliqué pour moi, mais je peux au moins te parler des variables de classe.

    Si name est une variable de classe et si tu cherches, de l'extérieur de la classe, à affecter à name une nouvelle valeur en préfixant avec une instance (ex: mod1.name=...), tu crées en fait une nouvelle variable d'instance (comme si tu l'avais déclarée dans la classe avec self.name) qui masque la variable de classe.

    Donc: si name est une variable de classe, il ne faut y accéder (de l'extérieur de la classe comme de l'intérieur des méthodes de la classe) qu'en la préfixant avec le nom de la classe: Model.name, ceci pour l'affectation et pour la lecture de sa valeur.

    Pour la lecture, il apparait qu'on peut accéder à la valeur de la variable de classe en la préfixant par une instance, mais seulement s'il n'existe pas une variable d'instance de même nom. C'est donc assez risqué, et il vaut mieux s'en tenir au nom de la classe.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  7. #7
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Si j'ai bien compris, tu veux accéder aux "fields" définis dans la classe.
    A priori, tu devrais pouvoir y accéder comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    object.__class__.<nom du champ>

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    271
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 271
    Points : 329
    Points
    329
    Par défaut
    En reprenant vos exemples je ferais ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    class Field:
        def __init__(self, name, type):
            self.__name = name
            self.__type = type
     
     
    class Model:
        def __init__(self):
            self.__field = Field(None, None)
     
        @property
        def name(self):
            return self.__field.__name
     
        @property
        def type(self):
            return self.__field.__type
     
        @property
        def field(self):
            return self.__field
     
    if __name__ == '__main__':
        mod1= Model()
        mod2= Model()
     
        mod1.name = "toto"
        mod1.type = "VARCHAR(250)"
     
        mod2.name = "titi"
        mod2.type = "VARCHAR(80)"
     
        print mod1
        print mod1.name
        print mod1.type
        print mod1.field
     
        print mod2
        print mod2.name
        print mod2.type
        print mod2.field

  9. #9
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    J'ai trouvé un petit orm. Regarde le source ca te donnera sûrement des pistes de travail.

    http://autumn-orm.org/

    Pour ma part j'aurais sûrement regardé du coté des metaclass.
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  10. #10
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Je suis cette file mais je ne suis toujours pas arrivé à comprendre quel est le problème posé et ce que je lis me rend perplexe.



    Dans wikipedia, ORM:
    object-relational mapping , est une technique de programmation informatique qui crée l'illusion d'une base de données orientée objet à partir d'une base de données relationnelle en définissant des correspondances entre cette base de données et les objets du langage utilisé. On pourrait le désigner par « correspondance entre monde objet et monde relationnel »
    À moins de devoir plonger dans l’étude des différentes sortes de SGBD, ceci ne m’éclaire pas sur le genre d’instructions et de résultats que tu vises obtenir.




    vérifier ou transformer le type de la valeur passée
    quid ?
    qu’est ce que ça veut dire ?





    Ce qui m’intrigue est que dans le premier message il y a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class utilisateur(object):
    nom= "default"
    ...........
     
    user1 =utilisateur()
    user2 =utilisateur()
    user1.nom = "nouveau"
    print user2.nom -> me retourne "nouveau"
    Mais je n’obtiens pas ce comportement avec le code suivant (j’ai essayé avec une old-style class aussi bien qu’avec une new-style class, c’est pareil)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class U(object):
        name = 'depart'
        def f(x):
            print repr(x)+' kilos'
     
    a = U()
    b = U()
     
    print 'U.name :',U.name
    print 'a.name :',a.name,type(a.name)
    print 'b.name :',b.name,type(b.name)
    print
    a.name = 70
    print 'U.name :',U.name
    print 'a.name :',a.name,type(a.name)
    print 'b.name :',b.name,type(b.name)
    U.name : depart
    a.name : depart <type 'str'>
    b.name : depart <type 'str'>

    U.name : depart
    a.name : 70 <type 'int'>
    b.name : depart <type 'str'>
    Ceci est en contradiction avec ce que tu décris dans #1, 3Dkermit, mais aussi avec ce que dit Tyrtamos
    Si name est une variable de classe et si tu cherches, de l'extérieur de la classe, à affecter à name une nouvelle valeur en préfixant avec une instance (ex: mod1.name=...), tu crées en fait une nouvelle variable d'instance (comme si tu l'avais déclarée dans la classe avec self.name) qui masque la variable de classe.
    Désolé, mais si «masque la variable de classe» signifie que toutes les instances se retrouvent avec la même nouvelle valeur affectée, le code suivant ne me donne pas ce résultat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    class K:
        name = 'jupiter'
        def fa(self,x):
            print 'aaa'+repr(x)
        def __init__(self,ki):
            self.nono = 'tintin '+repr(ki)
     
     
    print 40*'='+"\nCreation de 2 instance a et b de K: a = K(123) et b = K('fgh')"
    a = K(123)
    b = K('fgh')
    print '\ndir(K) =',dir(K)
    print 'dir(a) =',dir(a)
    print 'dir(b) =',dir(b)
    print 'K.name =',K.name
    print 'a.name =',a.name
    print 'b.name =',b.name
     
    print 40*'='+"\nCreation d'une variable d'instance ride dans a: a.ride = 90"
    a.ride = 90
    print '\ndir(K) =',dir(K)
    print 'dir(a) =',dir(a)
    print 'dir(b) =',dir(b)
    print 'K.name =',K.name
    print 'a.name =',a.name
    print 'b.name =',b.name
     
    print 40*'='+"\nInstruction a.name = 980"
    a.name = 980
    print '\ndir(K) =',dir(K)
    print 'dir(a) =',dir(a)
    print 'K.name =',K.name
    print 'a.name =',a.name
    print 'b.name =',b.name
     
    print 40*'='+"\nCreation d'une instance c de K: c = K(5463)"
    c = K(5463)
    print '\ndir(K) =',dir(K)
    print 'dir(a) =',dir(a)
    print 'dir(b) =',dir(b)
    print 'dir(c) =',dir(c)
    print 'K.name =',K.name
    print 'a.name =',a.name
    print 'b.name =',b.name
    print 'c.name =',c.name
     
    print 40*'='+"\nInstruction b.name = 'ouistiti'"
    b.name = 'ouistiti'
    print '\ndir(K) =',dir(K)
    print 'dir(a) =',dir(a)
    print 'dir(b) =',dir(b)
    print 'dir(c) =',dir(c)
    print 'K.name =',K.name
    print 'a.name =',a.name
    print 'b.name =',b.name
    print 'c.name =',c.name
    ========================================
    Creation de 2 instance a et b de K: a = K(123) et b = K('fgh')

    dir(K) = ['__doc__', '__init__', '__module__', 'fa', 'name']
    dir(a) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    dir(b) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    K.name = jupiter
    a.name = jupiter
    b.name = jupiter
    ========================================
    Creation d'une variable d'instance ride dans a: a.ride = 90

    dir(K) = ['__doc__', '__init__', '__module__', 'fa', 'name']
    dir(a) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono', 'ride']
    dir(b) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    K.name = jupiter
    a.name = jupiter
    b.name = jupiter
    ========================================
    Instruction a.name = 980

    dir(K) = ['__doc__', '__init__', '__module__', 'fa', 'name']
    dir(a) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono', 'ride']
    K.name = jupiter
    a.name = 980
    b.name = jupiter
    ========================================
    Creation d'une instance c de K: c = K(5463)

    dir(K) = ['__doc__', '__init__', '__module__', 'fa', 'name']
    dir(a) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono', 'ride']
    dir(b) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    dir(c) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    K.name = jupiter
    a.name = 980
    b.name = jupiter
    c.name = jupiter
    ========================================
    Instruction b.name = 'ouistiti'

    dir(K) = ['__doc__', '__init__', '__module__', 'fa', 'name']
    dir(a) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono', 'ride']
    dir(b) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    dir(c) = ['__doc__', '__init__', '__module__', 'fa', 'name', 'nono']
    K.name = jupiter
    a.name = 980
    b.name = ouistiti
    c.name = jupiter

    De plus, ceci n’est pas vérifié
    Pour la lecture, il apparait qu'on peut accéder à la valeur de la variable de classe en la préfixant par une instance, mais seulement s'il n'existe pas une variable d'instance de même nom.
    puisque K.name donne ’jupiter’ quel que soit ce qui s’est passé sur les instances.



    J’utilise Python 2.6.

    Il y a un réglage quelque part qui pourrait expliquer cette différence ?

    Le code de Antoine présente la même différence de résultat. Ça me rassure un peu sur ce que j’obtiens.

    Je remarque que moi et Antoine935 avançons des codes que d’autres peuvent faire tourner; Tyrtamos et 3Dkermit non, et c’est dommage.

    Si 3Dkermit n’obtient pas le résultat “naturel“, disons réplicable avec un code à se mettre sous la dent, n'est ce pas ce qui explique qu’un code avec property semble apporter une solution ? En fait, le code avec property d'Antoine donnerait son résultat, non pas de par le fait de property mais du fait que c’est le fonctionnement naturel. Non ? Où est-ce que je me trompe ou comprends mal ?






    Je ne comprends vraiment pas du tout le message #5. Il m’intéressait parce qu’il y est dit
    le code qui se rapproche le plus de ce que je veux :
    et dans le code qui suit on lit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    mod1= Model()
     
    mod2= Model()
    mod1.name = "toto"
    print mod2.name
    ..........."toto"
    c’est à dire ce que tu dis (en #1) obtenir et ne te convenant pas.......:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    user1 =utilisateur()
    user2 =utilisateur()
    user1.nom = "nouveau"
    print user2.nom -> me retourne "nouveau"


    Puis
    je voudrais avoir la même, mais pour une variable d'instance
    Qu’est ce que ça veut dire ? La même quoi ?


    mais quand j'assigne une chaine à ma variable name, cela "écrase" mon type field
    Ben oui. Si on change une variable, le type suit le changement. Quel sens aurait qu’il en soit autrement ?

    Cette réflexion me semble bien confirmer que ce que tu veux, c’est changer les valeurs de variables d’instances sans toucher à la variable de classe qui en a été le modèle à l’initialisation de l’instance. Mais c’est le comportement effectif et naturel que j’observe. Alors ..... ? Faux problème ?



    Quand nous aurons compris le problème et s’il se vérifiait qu’il est bien réel, je pense comme DelphiManiac qu’on devrait faire intervenir les metaclasses.


    PS

    Dans le code d’Antoine, message #3, n’est ce pas une drôle d’idée de créer une instance de la classe Model avec le nom réservé object ??

  11. #11
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Quand nous aurons compris le problème et s’il se vérifiait qu’il est bien réel, je pense comme DelphiManiac qu’on devrait faire intervenir les metaclasses.


    PS

    Dans le code d’Antoine, message #3, n’est ce pas une drôle d’idée de créer une instance de la classe Model avec le nom réservé object ??
    Bon, comme d'hab j'ai la flemme de lire le message dans son intégralité, alors je vais seulement réagir aux trois dernières lignes.

    Les métaclasses seraient certainement une solution viable.
    Hélas, un bon ORM se doit d'appliquer le moins de charges possible sur le code. Déjà qu'ici on force le développeur à dériver d'une classe, faudrait pas en plus lui infliger une métaclasse: les héritages peuvent devenirs compliqués si le développeur veut introduire sa propre métaclasse (conflits de metaclasses).

    Les ORM les plus populaires actuellement font le mouvement inverse: ce sont eux qui créent des sous classes. Ces sous classes réimplémentent les méthodes des modèles pour passer par la db, avec lazy instantiation etc... je vous passe les détails.
    Et comme on peut toujours remplacer un type par son sous-type, le développeur qui se sert de l'orm ne voit rien. Rien de rien.

    Cette inversion de processus permet plus de flexibilité dans le code utilisant l'orm, et ce pour plusieurs raisons. La première est que vous ne devez hériter d'aucune classe. La deuxième c'est qu'il est alors possible de changer le mapping avec un fichier xml ou dans les sources. Il existe plein d'autres raisons qui vous seront expliquées sur le net




    Effectivement, dans mon code j'utilise le nom object. C'est vrai, ce n'est pas forcément une bonne idée. Mais ça ne gène en rien si on ne crée pas de classes à la volée. D'autant plus que la variable créée a une portée limitée, donc ça n'affecte que localement.

  12. #12
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    En gros la plupart des orm déclarent les champs de la table sous jacentes sous formes de variable de classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Table1(object):
        Name = StringField()
        SurName = StringField()
    Si on s'en tiens à cela et que l'on instancie 2 fois cette classe, cela ne fonctionne pas.

    Il faut changer ces variables de classes en variables d'instance (par une metaclass d'après moi) en implémentant de plus un mécanisme d'accès (getter/setter) qui permettrais en plus de vérifier que les valeurs données soient bien du bon type.

    J'espère avoir bien résumé le problème.
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  13. #13
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    J'ai beau chercher, je ne vois décidément pas où ça coince:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    >>> class Field:
    ...     def __repr__(self):
    ...         return "Abstract field"
    ...
    >>> class StringField(Field):
    ...     def __repr__(self):
    ...         return "String field"
    ...
    >>> class Table(object):
    ...     name = StringField()
    ...     nickName = StringField()
    ...
    >>> t1 = Table()
    >>> t1.name = "Table une"
    >>> t1.nickName = "Ma petite table favorite"
    >>>
    >>> t2 = Table()
    >>> t2.name = "Table deux"
    >>> t2.nickName = "Ma table de bureau"
    >>>
    >>> Table.name
    String field
    >>> Table.nickName
    String field
    >>> t1.name
    'Table une'
    >>> t1.nickName
    'Ma petite table favorite'
    >>> t2.name
    'Table deux'
    >>> t2.nickName
    'Ma table de bureau'
    >>> t1.__class__.name
    String field
    >>> t1.__class__.nickName
    String field
    Aurais-tu un exemple concret pour illustrer le souci que tu évoques ?

  14. #14
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Field:
        def __repr__(self):
            return "Abstract field"
     
    class StringField(Field):
        def __repr__(self):
            return "String field"
     
    class Table(object):
        name = StringField()
        nickName = StringField()
     
    t1 = Table()
    print type(Table.name), id(Table.name)
    print type(t1.name), id(t1.name)
    t1.name = "Table une"
    print type(Table.name), id(Table.name)
    print type(t1.name), id(t1.name)
    Ici on voit le problème. Au départ t1.name est une instance de StringField, après l'assignation, c'est une instance de str.

    En gros avec t1.name = 'Table une", tu te retrouves avec deux "name", un pour la classe et un pour l'instance t1.

    Sur les premiers print, la variable de classe = la variable d'instance, après l'affectation, la variable d'instance à "écrasé" la variable d'instance. En fait elle ne l'écrase pas mais devient la valeur renvoyé en premier.
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  15. #15
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    D'où l'intérêt de lire tous les messages: voir #6 plus haut => http://www.developpez.net/forums/m4707579-6/.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  16. #16
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    @ DelphiMan

    C’est éclairant pour moi. Merci.
    Après, à moi d’étudier tout seul les setter et getter





    @ Antoine935

    Effectivement, dans mon code j'utilise le nom object. C'est vrai, ce n'est pas forcément une bonne idée. Mais ça ne gène en rien si on ne crée pas de classes à la volée. D'autant plus que la variable créée a une portée limitée, donc ça n'affecte que localement.
    Ah bon, d’accord.
    Ce n’est pas mon pli de me permettre des pratiques risquées mais si quelqu’un maîtrise bien son affaire après tout.....
    Je trouve juste qu’étant donné la réflexion qui revient souvent dans tes propos, on pourrait rétorquer «Et si le code doit être repris par quelqu’un d’autre et intégré dan un code englobant, est-ce que ça ne risque pas d’entrainer des problèmes ?»
    Mais bon, si quelqu’un maîtrise bien les choses, après tout....



    Pour le reste, merci mais j’avoue que ça me dépasse, et ça manque un peu de chair.



    D’un point de vue logique, c’est un peu dommage d’écrire
    Les métaclasses seraient certainement une solution viable.
    sans avoir lu mon message dans lequel je dis que le problème en lui-même ne m'est pas clair. Comment être sûr d’une solution à un problème mal cerné ?
    Comme bien souvent, mon premier problème est d’arriver à comprendre quel est le problème évoqué.

  17. #17
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    Je pense que cela doit fonctionner.

    Par contre, je n'ai pas testé à fond, pas sûr que je n'ai pas oublié un cas trivial qui fais planter !! Et encore moins sûr qu'il n'y ai pas un effet de bord auquel je n'ai pas pensé.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    # Ici le framework
    class BaseField(object):
        def _getvalue(self, obj, variablename):
            if obj.__dict__.has_key(variablename):
                return obj.__dict__[variablename]
            else:
                return None
     
        def _setvalue(self, obj, variablename, value):
            obj.__dict__[variablename] = value
     
    class StringField(BaseField):
        def _setvalue(self, obj, variablename, value):
            if value.startswith('A'):
                raise Exception ("Ne doit pas commencer par 'A'")
            super(StringField, self)._setvalue(obj, variablename, value)
     
    class MetaModel(type):
        def __init__(cls, name, bases, dct):
            class accessor(object):
                def __init__(self, variablename, reftofield):
                    self.variablename = variablename
                    self.reftofield = reftofield
                def _getvalue(self, obj):
                    return self.reftofield._getvalue(obj, "_" + self.variablename)
                    #return obj.__dict__[self.variablename]
                def _setvalue(self, obj, value):
                    self.reftofield._setvalue(obj, "_" + self.variablename, value)
                    #obj.__dict__[self.variablename] = value
     
            cls._fields = []
            for name, typ in dct.items():
                if issubclass(typ.__class__, BaseField):
                    cls._fields.append (name)
                    ref = getattr(cls, name)
                    acc = accessor(name, ref)
                    setattr(cls, name, property(acc._getvalue, acc._setvalue))
     
    class Model(object):
        __metaclass__ = MetaModel
     
     
     
    # Ici le code utilisateur
    class Table1(Model):
        name = StringField()
        nickName = StringField()
     
     
    try:
        t1 = Table1()
        t2 = Table1()
     
        t1.name = "t1.name"
        t2.name = "t2.name"
     
        for f in Table1._fields:
            print f
        print t1.name, type(t1.name)
        print t2.name, type(t2.name)
     
        t3 = Table1()
        t3.name = "AAAAA"
    except Exception, e:
        print e
    En gros, au moment de la création de la classe "Table1" (pas de l'instance), la metaclass parcours les attributs de la classe et pour ceux qui sont hérités de Field effectue le traitement suivant. Création d'une nouvelle 'property' s'appuyant sur une instance de accessor. Cette propriété stocke les valeurs de chacun des "Field" dans l'instance sous le nom "_" + nom_du_champ.

    Exemple :

    Si l'on part de la déclaration d'un champ (name = StringField()), la classe se voit compléter d'une propriété d'instance de nom "name" et d'une variable d'instance "_name".

    La propriété "name" utilise les setter/getter de accessor pour appeler les méthodes de l'objet StringField. L'objet StringField stocke au sein de l'instance de la table les valeurs dans la variable d'instance "_name".

    En espérant que ce soit pas trop confus, c'est pas évident à expliquer !!
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  18. #18
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    Citation Envoyé par DelphiManiac Voir le message
    En gros la plupart des orm déclarent les champs de la table sous jacentes sous formes de variable de classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Table1(object):
        Name = StringField()
        SurName = StringField()
    Si on s'en tiens à cela et que l'on instancie 2 fois cette classe, cela ne fonctionne pas.

    Il faut changer ces variables de classes en variables d'instance (par une metaclass d'après moi) en implémentant de plus un mécanisme d'accès (getter/setter) qui permettrais en plus de vérifier que les valeurs données soient bien du bon type.

    J'espère avoir bien résumé le problème.

    Bonjour tout le monde,

    j'avoue que j'ai du mal à définir le problème, donc du coup du mal à l'exposé

    mais le poste ci-dessus DelphiManiac exprime pleinement mon problème et mes attentes

    Merci pour votre acharnement à comprendre et vos réponses

    Kermit

  19. #19
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Points : 16
    Points
    16
    Par défaut
    ok,

    la solution de DelphiManiac me plait beaucoup.

    je m'en vais de ce pas le tester à plus grande échelle ( et essayer de la décortiquer un peu )

    merci à tous

    Kermit

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. C++ classe et attributs
    Par kouack dans le forum C++
    Réponses: 7
    Dernier message: 24/04/2008, 14h43
  2. Propriétés d'une classe selon attribut
    Par Papy214 dans le forum Windows Forms
    Réponses: 2
    Dernier message: 10/03/2008, 17h02
  3. Quels classes utiliser pour remplacer des classes qui sont propriété de Sun
    Par danyboy85 dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 21/11/2007, 16h36
  4. Classe fille sans propriété supplémentaire
    Par boutss dans le forum Langage
    Réponses: 6
    Dernier message: 28/03/2007, 09h50
  5. Réponses: 5
    Dernier message: 05/05/2006, 09h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo