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 :

Dump d'une classe python


Sujet :

Python

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 9
    Points : 8
    Points
    8
    Par défaut Dump d'une classe python
    Je suis entrain d'écrire un module pour "dumper" n'importe quel objet python, mais je coince sur un cas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class A:
        class B:
            pass
     
    def dump_class(c):
         print c.__module__ + '.' + c.__name__
     
    >>> dump_class(A)
    __main__.A
     
    >>> dump_class(A.B)
    __main__.B
    Comment faire pour afficher __main__.A.B au lieu de __main__.B ?

  2. #2
    Membre expérimenté Avatar de pacificator
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 074
    Points : 1 728
    Points
    1 728
    Par défaut
    Bonjour,

    Il existe pickle qui permet de sérialiser des objets python et dont une des limitations est de ne pas pouvoir serialiser les "nested class" tel que tu veux le faire:
    The following types can be pickled:
    * ...
    * classes that are defined at the top level of a module
    Je pense donc qu'il va être difficile de passer outre cette limitation.

    Il y a un patch pour pickle qui est proposé içi:
    + // Nested class workaround
    + // With the python code below::
    + // class A:
    + // class B:
    + // pass
    + // Python 2.6 erroneously set the B.__name__ to "B" instead of "A.B".
    +
    + // Furthermore, upon pickling (here in save_global)
    + // *and* unpickling (in load_global) a class
    + // with name "A.B" in a module mod, the standard
    + // cPickle module searches for "A.B" in mod.__dict__
    + // instead of looking up "A" and then "B" in the result.
    + //
    + // The code below makes a library callback to a
    + // function that searches recursively for B in the
    + // classes and nested classes of mod, set the name for
    + // B to its appropriate value A.B, and inserts A.B in
    + // mod.__dict__ (a hack).
    + //
    + // This library callback will only occur upon the
    + // first time the class A.B is pickled, so the
    + // overhead is negligible, and this code was much
    + // easier to write in plain python.
    + //
    + // Todo:
    + // - Fix Python, and cPickle
    + // - In the mean time, have some Python - C API expert
    + // rewrite the callback below
    "Etre conscient de la difficulté permet de l'éviter.."
    Lao-Tseu.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par pacificator Voir le message
    Bonjour,

    Il existe pickle qui permet de sérialiser des objets python et dont une des limitations est de ne pas pouvoir serialiser les "nested class" tel que tu veux le faire:Je pense donc qu'il va être difficile de passer outre cette limitation.
    C'est bien ce que je craignais.

    Citation Envoyé par pacificator Voir le message
    Il y a un patch pour pickle qui est proposé içi:
    Merci beaucoup, je vais voir ce que je peux faire avec.

  4. #4
    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
    J’ai pondu ce qui suit en partant de l’idée que si une sous-classe B ne contient pas l’information de la classe englobante A qui la contient et qu’il n’y a aucune méthode qui puisse sortir le nom de A de l’objet B,
    alorsc à défaut de pouvoir obtenir cette info quand on est "dedans" (càd qu’on n’a qu’un objet classe B sous la main),
    il fallait nécessairement établir cette information en se situant “à l’extérieur“, c’est à dire établir le dictionnaire des “chemins“ de toutes les classes avant tout.

    Au lieu d’une fonction, le code utilise un dictionnaire.

    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
    class A:
        class B:
            class C:
                pass
     
    class W:
        class X:
            class XY:
                pass
            class XZ:
                pass
        class H:
            class HY:
                class HYZ:
                    pass
                class HYZZ:
                    pass
            class HZZTop:
                pass
     
    dump_class = {'__main__':'__main__'}
     
    def lekl(dico,nom):
        for v in dico.values():
            if repr(v)[1:6]=='class':
                dump_class[v.__name__] = dump_class[nom]+'.'+v.__name__
                lekl(v.__dict__,v.__name__)
     
    lekl(globals(),'__main__')
     
     
     
    print 'items du dictionnaire dump_class :\n'
    for x in dump_class.items():
        print x
     
     
    print '\n======================================\n'
    for y in W.H.__dict__.values():
        if repr(y)[1:6]=='class':
            print dump_class[y.__name__]
    >>>
    items du dictionnaire dump_class :

    ('A', '__main__.A')
    ('C', '__main__.A.B.C')
    ('B', '__main__.A.B')
    ('H', '__main__.W.H')
    ('XZ', '__main__.W.X.XZ')
    ('XY', '__main__.W.X.XY')
    ('HY', '__main__.W.H.HY')
    ('HYZZ', '__main__.W.H.HY.HYZZ')
    ('W', '__main__.W')
    ('__main__', '__main__')
    ('X', '__main__.W.X')
    ('HYZ', '__main__.W.H.HY.HYZ')
    ('HZZTop', '__main__.W.H.HZZTop')

    ======================================

    __main__.W.H.HY
    __main__.W.H.HZZTop
    >>>
    Je trouve bizarre de vouloir faire sortir __main__.A.B à partir du nom de la classe A.B :
    si tu sais que la classe a pour nom A.B , tu n’as pas besoin d’une fonction qui puisse le trouver toute seule........

    Je présume donc que ton besoin sera de faire écrire le “chemin“ d’une classe, le “dump“ comme tu l’appelles, d’une classe sans connaître le nom de cette classe.

    L’exemple d’exploration de la classe W.H que j’ai mis à la fin ( for y in W.H.__dict__.values(): etc ) montre que le code ci-dessus fournit ce “dump“ même sans connaître le nom de la classe a piori. C’est le code qui établit la liste de toutes les classes et leur dump correspondant.



    Nota Bene: mon code n’est pas tout à fait ce que tu recherches, c’est à dire une fonction dump prenant un argument qui est une classe (du moins c’est ce qu’il m’apparaît).

    Dans mon code, je n’ai pas voulu mettre des objets comme clés du dictionnaire dump_class: ses clés sont donc les noms des classes.



    Je ne sais pas si ça pourra t’aider. Je ne vois pas comment on peut faire autrement.

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Je trouve bizarre de vouloir faire sortir __main__.A.B à partir du nom de la classe A.B :
    si tu sais que la classe a pour nom A.B , tu n’as pas besoin d’une fonction qui puisse le trouver toute seule........

    Je présume donc que ton besoin sera de faire écrire le “chemin“ d’une classe, le “dump“ comme tu l’appelles, d’une classe sans connaître le nom de cette classe.
    C'est tout à fait ça !

    Merci pour ton code.
    Ta méthode me parait bien pour dumper les classes d'un module a priori.
    Si je veux faire une fonction dump() qui accepte n'importe quel objet (dont les classes), je vais être obligé de parser les globals de chaque module de chaque classe pour enregistrer tous les "chemins" ce qui risque d'être très couteux.
    Mais comme tu le dis, il n'y a peut-être pas d'autres solutions

  6. #6
    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 ne comprends pas cette expression:
    chaque module de chaque classe
    Qu’est ce que c’est le module d’une classe ?







    ce qui risque d'être très couteux.
    Je ne crois pas. Pourquoi serait-ce très coûteux ?



    Parcourir un dictionnaire, ce qu’est globals() , est rapide.
    Même pour un programme comportant beaucoup d’objets, je pense que l’examen de globals() peut être assez rapide.

    J’ai écrit le code suivant pour le vérifier:

    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
    66
    67
    68
    69
    70
    71
    72
    73
    74
    from time import clock
    from random import sample
    from string import ascii_lowercase as alphabet
     
    i = 0
    for c1 in alphabet:
        for c2 in alphabet:
            for c3 in alphabet:
                for c4 in alphabet:
                    if i%10000==0:
                        print i
                    nom = c1+c2+c3+c4
                    if nom =='axaa':
                        i += 1
                        class Caxaa:
                            pass
                    elif nom =='dyui':
                        i += 1
                        class Cdyui:
                            pass
                    elif nom=='fdaw':
                        i += 1
                        class Cfdaw:
                            pass
                    elif nom=='dtvx':
                        i += 1
                        class Cdtvx:
                            pass
                    elif nom=='klwa':
                        i += 1
                        class Cklwa:
                            pass
                    elif nom!='repr' and nom!='type':
                        i += 1
                        globals()[nom] = '*'+''.join(sample(alphabet,4))
     
    print 'i = '+str(i)
    print 'dernier nom :',nom,'  et sa valeur :',globals()[nom]
     
    print '\n\nTests'
    print aaaa,fdde,drwa,krxe
    print 'Caxaa' in globals(),globals()['Caxaa'],type(globals()['Caxaa'])
    print 'Cdyui' in globals(),globals()['Cdyui'],type(globals()['Cdyui'])
    print 'Cfdaw' in globals(),globals()['Cfdaw'],type(globals()['Cfdaw'])
    print 'Cdtvx' in globals(),globals()['Cdtvx'],type(globals()['Cdtvx'])
    print 'Cklwa' in globals(),globals()['Cklwa'],type(globals()['Cklwa'])
    print 'dertyu' in globals()
     
     
     
     
    dump_class = {'__main__':'__main__'}
    def lekl(dico,nom):
        for v in dico.values():
            try:
                if repr(v)[1:6]=='class':
                    dump_class[v.__name__] = (dump_class[nom]+'.'+v.__name__,v.__name__)
                    lekl(v.__dict__,v.__name__)
            except:
                pass
     
    te = clock()
    lekl(globals(),'__main__')
    tf = clock()
     
     
     
    print '\n\n\n=========================================================\n'\
          +'items du dictionnaire dump_class :\n'
    for x in dump_class.items():
        print x
     
    print '\nconstitution du dictionnaire dump_class effectuee en:\n     ',tf-te,' secondes'\
          +'\n========================================================='
    il consiste essentiellement à

    - créer 26*26*26*26 - 2 = 456974 objets
    donc autant de noms dans le dictionnaire globals()
    - puis à mesurer le temps nécessaire à l’examen de globals() pour constituer le dictionnaire dump_class suivant la méthode que j’ai écrite plus haut.
    Le -2 correspond aux noms repr et type que l’on évite de redéfinir sinon le programme ne tourne plus correctement.

    Sur les 456974 objets, 5 sont des classes pour fournir à la fonction lekl() quelque chose à se mettre sous la dent,
    les autres sont des objets strings dont les valeurs, déterminées aléatoirement sont du genre ’*ferq’, et dont les noms sont à 4 lettres.



    Ma bécane étant un vieux truc dont le temps d'exécution n’est pas représentatif,
    est-ce que quelqu’un peut faire tourner ce code et donner le temps qu’il prend sur sa machine SVP (donné par le programme) ?

    Cela devrait être inférieure à la seconde pour examiner près de 457000 items dans le dictionnaire globals().

  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
    Je viens de tester ton code sur ma machine, avec Python 2.4 et 2.6
    J'ai un Vista 32bit avec Intel Core 2 Duo T6400 (2.00 GHz, 2Mo cache L2).
    Il y a environ 775 threads, pour 75 processus.

    Il faut entre 0.25 et 0.3 secondes de manière générale.
    Le processus a consommé 50% des ressources CPU disponibles pdt l'exécution.

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Je ne comprends pas cette expression:

    Qu’est ce que c’est le module d’une classe ?
    Je voulais juste parler de l'attribut __module__ d'une classe.
    En effet si j'écris une fonction dump dans un fichier "dump.py", une classe A dans le fichier "aa.py" et une classe B dans le fichier "bb.py".
    Si maintenant j'écris le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    from dump import dump
    import aa
    import bb
     
    dump( aa.A())
    dump( bb.B())
    Je viens être obligé dans ma fonction dump() de parcourir le dictionnaire globals() de chaque module (A.__module__ == 'aa', B.__module__ == 'bb').
    Et donc à chaque nouvel appel de dump(), je dois vérifier s'il ne s'agit pas d'une classe avec un nouveau module et donc un nouveau dictionnaire.

    Citation Envoyé par eyquem Voir le message
    Je ne crois pas. Pourquoi serait-ce très coûteux ?
    Mais effectivement tu as raison, ce n'ai pas forcément si couteux !

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

Discussions similaires

  1. [Python 2.X] acceder à tout les attribut d'une classe python 2.5
    Par tsumey dans le forum Général Python
    Réponses: 5
    Dernier message: 11/06/2015, 11h38
  2. apelle en C à partir d'une classe faite en python
    Par julien25 dans le forum Interfaçage autre langage
    Réponses: 4
    Dernier message: 16/03/2009, 22h24
  3. python C API: convertir une struct C en Class python
    Par dmichel dans le forum Interfaçage autre langage
    Réponses: 11
    Dernier message: 25/06/2008, 16h30
  4. [Reflexion] Comment récupérer une class via son chemin python
    Par anthyme dans le forum Général Python
    Réponses: 2
    Dernier message: 27/12/2007, 13h16
  5. Definition d'une classe python dans plusieurs fichiers
    Par wfargo dans le forum Général Python
    Réponses: 3
    Dernier message: 05/12/2006, 23h03

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