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 :

Fonction "is iterable" et introspection


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut Fonction "is iterable" et introspection
    Bonjour à tous !

    Question simple :
    Y a-t-il un moyen de demander à un objet si il est iterable ?
    Il y a bien callable, pourquoi pas iterable ?

    Petite question subsidiaire : pourquoi certains objets ont un nom (attribut __name__) et d'autres pas ?

    Le but ultime de tout ça, c'est d'écrire une fonction DeepPrint qui affiche recursivement tous les membres d'un objet.

    Le but ultime du but ultime, c'est d'écrire une fonction DeepCompare qui compare 2 instances, membre par membre, recursivement.

  2. #2
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Question simple :
    Y a-t-il un moyen de demander à un objet si il est iterable ?
    Il y a bien callable, pourquoi pas iterable ?
    Il faut vérifier la présence de la méthode __iter__, si non, vérifier la présence de la méthode __getitem__, où __getitem__ accepterait comme valeur de clé, des ints partant de 0.

    ou bien faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    try:
        iter(obj)
        isiterable=1
    except:
        isiterable=0
    Petite question subsidiaire : pourquoi certains objets ont un nom (attribut __name__) et d'autres pas ?
    Sûrement parce que certaines classes / fonctions ont été écrites en C et n'incluaient pas cet attribut.


    Le but ultime de tout ça, c'est d'écrire une fonction DeepPrint qui affiche recursivement tous les membres d'un objet.
    C'est marrant ça, j'me suis ammuser à faire un truc un peu similaire cette nuit, je sais pas si ça pourra t'être utile... (ou plutôt être utile tout court...)
    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
    def moduleAnalyser(module):
        for e in dir(module):
            tp=str(type(eval('%s.%s'%(module.__name__,e))))
            if 'func' in tp:
                yield module.__name__+'.'+e, 'f'
            elif "'type'>" in tp:
                yield module.__name__+'.'+e, 'c'
                for i in classAnalyser(eval('%s.%s'%(module.__name__,e))):
                    yield '%s.%s'%(module.__name__,i[0]),i[1]
            elif 'class' in tp:
                yield module.__name__+'.'+e, 'ci: %s'%eval('module.%s.__class__'%e)
                for i in classAnalyser(eval('module.%s.__class__'%e)):
                    yield module.__name__+'.'+i[0], i[1]
            else:
                yield module.__name__+'.'+e, 'v'
     
    def classAnalyser(cls):
        for e in dir(cls()):
            tp=str(type(eval('cls().%s'%(e))))
            if e!='__class__':
                if 'func' in tp:
                    yield cls.__name__+'().'+e, 'f'
                elif "'type'>" in tp:
                    yield cls.__name__+'().'+e, 'c'
                    for i in classAnalyser(eval('cls().%s'%e)):
                        yield '%s.%s'%(cls.__name__+'()', i[0]), i[1]
                elif 'method' in tp:
                    yield cls.__name__+'().'+e, 'm'
                elif 'class' in tp:
                    yield cls.__name__+'().'+e, 'ci: %s'%eval('cls().%s.__class__'%e)
                    for i in classAnalyser(eval('cls().%s.__class__'%e)):
                        yield cls.__name__+'().'+i[0], i[1]
                else:
                    yield cls.__name__+'().'+e, 'a'

  3. #3
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Merci pour tes réponses !

    J'ai essayé ta fonction classAnalyser avec ces petites classes là :
    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 TestSubClass:
        def __init__(self,i):
            self.s0 = 'hello'+str(i)
            self.i0 = i
            self.d0 = i/3.0
            self.l0 = [ i+1,i+2.0,str( i+3 )]
     
    class TestClass:
        def __init__(self):
            self.s = 'hello'
            self.i = 321
            self.d = 3.14159
            self.l = [ 1,2.345,'world !',TestSubClass(100)]
            self.c = TestSubClass(200)
     
    for i in classAnalyser( TestClass ) : print i
    et j'obtiens ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ('TestClass().__doc__', 'a')
    ('TestClass().__init__', 'm')
    ('TestClass().__module__', 'a')
    ('TestClass().c', 'a')
    ('TestClass().d', 'a')
    ('TestClass().i', 'a')
    ('TestClass().l', 'a')
    ('TestClass().s', 'a')
    Je n'ai pas l'impression qu'il visite récursivement les sous objets de ma classe.
    J'ai raté quelque chose ?

    D'autre part, à propos de l'attribut __name__, je ne suis pas sûr qu'il y ait un rapport avec l'implémentation C parce que même mes classes en pur python n'en ont pas...

  4. #4
    Membre Expert
    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
    Par défaut
    Hello,

    J’ai trouvé isSequenceType(o) dans le module operator.

    Mais je ne comprends pas tout du commentaire:


    isSequenceType(o)

    Returns true if the object o supports the sequence protocol. This returns true for all objects which define sequence methods in C, and for all instance objects defining __getitem__. Warning: There is no reliable way to test if an instance supports the complete sequence interface since the interface itself is ill-defined. This makes this test less useful than it otherwise might be.

    Quelques essais
    sur une chaîne, une liste, un tuple, ça renvoie True
    sur un entier, sur enumerate(), sur un générateur, ça renvoie False

  5. #5
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    D'autre part, à propos de l'attribut __name__, je ne suis pas sûr qu'il y ait un rapport avec l'implémentation C parce que même mes classes en pur python n'en ont pas...
    Alors ça doit être parce que ce ne sont pas des new-style class (héritant d'object ou autre classes dérivant de cette dernière)

    EDIT : de toute façon c'est vachement bancal en fait, à moins de définir que des paramètres par défaut pour __init__, et encore... y'a de grosses limitations :
    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 TestSubClass(object):
        def __init__(self,i):
            self.s0 = 'hello'+str(i)
            self.i0 = i
            self.d0 = i/3.0
            self.l0 = [ i+1,i+2.0,str( i+3 )]
     
    class TestClass(object):
        def __init__(self):
            self.s = 'hello'
            self.i = 321
            self.d = 3.14159
            self.l = [ 1,2.345,'world !',TestSubClass(100)]
            self.c = TestSubClass(200)
     
    for i in classAnalyser( TestClass ) : print i
    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
    ('TestClass().__delattr__', 'm')
    ('TestClass().__dict__', 'a')
    ('TestClass().__doc__', 'a')
    ('TestClass().__format__', 'f')
    ('TestClass().__getattribute__', 'm')
    ('TestClass().__hash__', 'm')
    ('TestClass().__init__', 'm')
    ('TestClass().__module__', 'a')
    ('TestClass().__new__', 'f')
    ('TestClass().__reduce__', 'f')
    ('TestClass().__reduce_ex__', 'f')
    ('TestClass().__repr__', 'm')
    ('TestClass().__setattr__', 'm')
    ('TestClass().__sizeof__', 'f')
    ('TestClass().__str__', 'm')
    ('TestClass().__subclasshook__', 'f')
    ('TestClass().__weakref__', 'a')
    ('TestClass().c', "ci: <class '__main__.TestSubClass'>")
     
    Traceback (most recent call last):
      File "C:/Documents and Settings/N.tox/Bureau/t.py", line 35, in <module>
        for i in classAnalyser( TestClass ) : print i
      File "C:/Documents and Settings/N.tox/Bureau/t.py", line 15, in classAnalyser
        for i in classAnalyser(eval('cls().%s.__class__'%e)):
      File "C:/Documents and Settings/N.tox/Bureau/t.py", line 2, in classAnalyser
        for e in dir(cls()):
    TypeError: __init__() takes exactly 2 arguments (1 given)
    avec paramètre 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
    class TestSubClass(object):
        def __init__(self,i=0):
            self.s0 = 'hello'+str(i)
            self.i0 = i
            self.d0 = i/3.0
            self.l0 = [ i+1,i+2.0,str( i+3 )]
     
    class TestClass(object):
        def __init__(self):
            self.s = 'hello'
            self.i = 321
            self.d = 3.14159
            self.l = [ 1,2.345,'world !',TestSubClass(100)]
            self.c = TestSubClass(200)
     
    for i in classAnalyser( TestClass ) : print i
    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
    ('TestClass().__delattr__', 'm')
    ('TestClass().__dict__', 'a')
    ('TestClass().__doc__', 'a')
    ('TestClass().__format__', 'f')
    ('TestClass().__getattribute__', 'm')
    ('TestClass().__hash__', 'm')
    ('TestClass().__init__', 'm')
    ('TestClass().__module__', 'a')
    ('TestClass().__new__', 'f')
    ('TestClass().__reduce__', 'f')
    ('TestClass().__reduce_ex__', 'f')
    ('TestClass().__repr__', 'm')
    ('TestClass().__setattr__', 'm')
    ('TestClass().__sizeof__', 'f')
    ('TestClass().__str__', 'm')
    ('TestClass().__subclasshook__', 'f')
    ('TestClass().__weakref__', 'a')
    ('TestClass().c', "ci: <class '__main__.TestSubClass'>")
    ('TestClass().TestSubClass().__delattr__', 'm')
    ('TestClass().TestSubClass().__dict__', 'a')
    ('TestClass().TestSubClass().__doc__', 'a')
    ('TestClass().TestSubClass().__format__', 'f')
    ('TestClass().TestSubClass().__getattribute__', 'm')
    ('TestClass().TestSubClass().__hash__', 'm')
    ('TestClass().TestSubClass().__init__', 'm')
    ('TestClass().TestSubClass().__module__', 'a')
    ('TestClass().TestSubClass().__new__', 'f')
    ('TestClass().TestSubClass().__reduce__', 'f')
    ('TestClass().TestSubClass().__reduce_ex__', 'f')
    ('TestClass().TestSubClass().__repr__', 'm')
    ('TestClass().TestSubClass().__setattr__', 'm')
    ('TestClass().TestSubClass().__sizeof__', 'f')
    ('TestClass().TestSubClass().__str__', 'm')
    ('TestClass().TestSubClass().__subclasshook__', 'f')
    ('TestClass().TestSubClass().__weakref__', 'a')
    ('TestClass().TestSubClass().d0', 'a')
    ('TestClass().TestSubClass().i0', 'a')
    ('TestClass().TestSubClass().l0', 'a')
    ('TestClass().TestSubClass().s0', 'a')
    ('TestClass().d', 'a')
    ('TestClass().i', 'a')
    ('TestClass().l', 'a')
    ('TestClass().s', 'a')
    le plus relou, c'est que je me souviens même plus pourquoi j'avais créer ces fonctions... faut qu'j'arrête la boisson moi...

  6. #6
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Finalement, j'ai à peu près réussi à coder la fonction que je voulais.
    Ce qui est rigolo, c'est qu'on ne retombe pas du tout sur la même approche...
    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
    def iterable ( obj ):
        try    : iter( obj )
        except : return False
        return True
     
    def DeepPrint ( a,name='',indent=0 ):
        if hasattr( a,'__dict__' ):
            for i in a.__dict__.items():
                n,e,v = i[0],getattr( a,i[0] ),i[1]
                if not isinstance( e,basestring ) and iterable( e ):
                    print ' '*indent,n,type( e ),':'
                    for i in e :
                        DeepPrint( i,'',indent+4 )
                elif hasattr( e,'__dict__' ):
                    print ' '*indent,n,type( e )
                    DeepPrint( e,n,indent+4 )
                else:
                    print ' '*indent,n,type( e ),str( v )
        elif hasattr( a,'__name__'):
            print ' '*indent,a.__name__,type( a ),str( a )
        else:
            print ' '*indent,name,type( a ),str( a )
    Dis moi ce que tu en penses...

    Pour revenir à l'attribut __name__, je n'ai aucune new-style class dans mon code...

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

Discussions similaires

  1. Quote et double quote
    Par aktos dans le forum Langage
    Réponses: 8
    Dernier message: 05/01/2007, 19h55

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