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 :

utilisation de inspect.getouterframes


Sujet :

Python

  1. #1
    Membre éprouvé Avatar de awalter1
    Inscrit en
    Août 2004
    Messages
    994
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 994
    Par défaut utilisation de inspect.getouterframes
    Bonjour,
    J'ai une application en python/gtk (python 2.7).
    j'ai une erreur déclenché dan la procédure suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def abstract():
     
        import inspect
     
        caller = inspect.getouterframes(inspect.currentframe())[1][3]
        print "currentframe=",inspect.currentframe()
        print "getouterframes="
        for i in inspect.getouterframes(inspect.currentframe()):
    	print i
     
        print "getouterframes[1][3]=",inspect.getouterframes(inspect.currentframe())[1][3]
        print
        raise NotImplementedError(caller + ' must be implemented in subclass')
    J'ai rajouté les print afin d'avoir les détails sur ce que retourne les fonctions d'inspect.
    En réalité je ne comprends pas pourquoi une exception est levée et comment l'interprêter. Voici l'erreur signalée :
    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
    currentframe= <frame object at 0x9ed8d9c>
    getouterframes=
    (<frame object at 0x9ed8d9c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 37, 'abstract', ['    for i in inspect.getouterframes(inspect.currentframe()):\n'], 0)
    (<frame object at 0x9f0297c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 313, 'GenericPanelGet_AllPages', ['\t\tabstract()\n'], 0)
    (<frame object at 0x9fd251c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 323, 'GenericPanelGet_SamePages', ['\t\t\tfor page in panel.GenericPanelGet_AllPages():\n'], 0)
    (<frame object at 0x9ee64a4>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/page.py', 455, 'PageWinDialogReturn', ['\t\tfor page in self.f_GetSamePages():\n'], 0)
    (<frame object at 0x9fc8cc4>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py', 398, 'WinDialogCallback', ['\t\t\tcallbackExit(True)\n'], 0)
    (<frame object at 0x9bab8ec>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py', 701, 'WinDialogCallback', ['\t\tWinDialogEdition__.WinDialogCallback(self, dialogWidget, response, callbackExit)\n'], 0)
    (<frame object at 0x9b05254>, './HMI/nedi.py', 322, 'ApplicationRun', ['\t\tgtk.main()\n'], 0)
    (<frame object at 0x92b07d4>, './HMI/nedi.py', 858, '<module>', ['\tnedi.ApplicationRun()\n'], 0)
    getouterframes[1][3]= GenericPanelGet_AllPages
     
    Traceback (most recent call last):
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py", line 701, in WinDialogCallback
        WinDialogEdition__.WinDialogCallback(self, dialogWidget, response, callbackExit)
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py", line 398, in WinDialogCallback
        callbackExit(True)
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/page.py", line 455, in PageWinDialogReturn
        for page in self.f_GetSamePages():
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 323, in GenericPanelGet_SamePages
        for page in panel.GenericPanelGet_AllPages():
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 313, in GenericPanelGet_AllPages
        abstract()
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 41, in abstract
        raise NotImplementedError(caller + ' must be implemented in subclass')
    NotImplementedError: GenericPanelGet_AllPages must be implemented in subclass
    Je lis que GenericPanelGet_AllPages (qui est bien une fonction de mon appli) doit être implémentée, que cela signifie t'il ?
    Ma fonction GenericPanelGet_AllPages est très simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	def GenericPanelGet_AllPages(self):
    		abstract()
    Quelqu'un peut t'il m'éclairer ?
    merci

  2. #2
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Ben en fait il n'y a pas d'erreur...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	def GenericPanelGet_AllPages(self):
    		abstract()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def abstract():
        ....
        raise NotImplementedError(caller + ' must be implemented in subclass')
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 41, in abstract
        raise NotImplementedError(caller + ' must be implemented in subclass')
    NotImplementedError: GenericPanelGet_AllPages must be implemented in subclass
    C'est vous qui la générez dans abstract (raise)

    Ou je n'ai pas compris la question.

    @+

  3. #3
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Maintenant si la question est sur inspect celui-ci fait bien son travail qui est de retrouver les informations sur le code:
    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
    currentframe= <frame object at 0x9ed8d9c>
    getouterframes=
    (<frame object at 0x9ed8d9c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 37, 'abstract', ['    for i in inspect.getouterframes(inspect.currentframe()):\n'], 0)
    (<frame object at 0x9f0297c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 313, 'GenericPanelGet_AllPages', ['\t\tabstract()\n'], 0)
    (<frame object at 0x9fd251c>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py', 323, 'GenericPanelGet_SamePages', ['\t\t\tfor page in panel.GenericPanelGet_AllPages():\n'], 0)
    (<frame object at 0x9ee64a4>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/page.py', 455, 'PageWinDialogReturn', ['\t\tfor page in self.f_GetSamePages():\n'], 0)
    (<frame object at 0x9fc8cc4>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py', 398, 'WinDialogCallback', ['\t\t\tcallbackExit(True)\n'], 0)
    (<frame object at 0x9bab8ec>, '/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py', 701, 'WinDialogCallback', ['\t\tWinDialogEdition__.WinDialogCallback(self, dialogWidget, response, callbackExit)\n'], 0)
    (<frame object at 0x9b05254>, './HMI/nedi.py', 322, 'ApplicationRun', ['\t\tgtk.main()\n'], 0)
    (<frame object at 0x92b07d4>, './HMI/nedi.py', 858, '<module>', ['\tnedi.ApplicationRun()\n'], 0)
    getouterframes[1][3]= GenericPanelGet_AllPages
     
    Traceback (most recent call last):
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py", line 701, in WinDialogCallback
        WinDialogEdition__.WinDialogCallback(self, dialogWidget, response, callbackExit)
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/windialogedition.py", line 398, in WinDialogCallback
        callbackExit(True)
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/page.py", line 455, in PageWinDialogReturn
        for page in self.f_GetSamePages():
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 323, in GenericPanelGet_SamePages
        for page in panel.GenericPanelGet_AllPages():
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 313, in GenericPanelGet_AllPages
        abstract()
      File "/rsynergy/ccm_wa/NEDI-ACE2010A_prep/NEDI/HMI/genericpanel.py", line 41, in abstract

  4. #4
    Membre éprouvé Avatar de awalter1
    Inscrit en
    Août 2004
    Messages
    994
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 994
    Par défaut
    Ok merci
    donc en fait cela fait ce qui est demandé dans le code, mais je dois commenter la ligne ou il y a le raise car sinon l'appli part en erreur et je ne sais pas comment l'éviter.

  5. #5
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    A vrais dire je ne comprend pas la question et le but d'abstract*...
    C'est pour tester inspect ?
    Cherchez vous a faire quelque chose de précis ?

    *Qui au passage est une fonction, pas une procédure: Pas de 'procédure' en Python puisque cela 'retourne' None

  6. #6
    Membre éprouvé Avatar de awalter1
    Inscrit en
    Août 2004
    Messages
    994
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 994
    Par défaut
    Comme je reprends un code qui n'est pas de moi, je ne sais pas non plus la raison de cette méthode abstract() si ce n'est de détecter les cas ou un héritage aurait du être fait et ne l'ai pas ...

  7. #7
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Et utiliser inspect pour cela alors qu'il y a __mro__ ?
    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
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    #
    #
    import inspect
     
     
    def abstract():
        caller = inspect.getouterframes(inspect.currentframe())[1][3]
        print "currentframe=", inspect.currentframe()
        print "getouterframes="
        for i in inspect.getouterframes(inspect.currentframe()):
            print i
        print "getouterframes[1][3]=", inspect.getouterframes(inspect.currentframe())[1][3]
     
     
    class A:
        pass
     
    class B:
        pass
     
    class C(A, B):
        pass
     
    class D(C, object):
        def getframe(self):
            abstract()
     
    d = D()
    d.getframe()
    print "object.__mro__", D.__mro__
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    currentframe= <frame object at 0x9ddd55c>
    getouterframes=
    (<frame object at 0x9ddd55c>, 'testdesc.py', 12, 'abstract', ['    for i in inspect.getouterframes(inspect.currentframe()):\n'], 0)
    (<frame object at 0x9ddd404>, 'testdesc.py', 28, 'getframe', ['        abstract()\n'], 0)
    (<frame object at 0x9da27ac>, 'testdesc.py', 31, '<module>', ['d.getframe()\n'], 0)
    getouterframes[1][3]= getframe
    object.__mro__ (<class '__main__.D'>, <class __main__.C at 0xb744c29c>, <class __main__.A at 0xb76da62c>, <class __main__.B at 0xb744c26c>, <type 'object'>)
    ?

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par awalter1 Voir le message
    Comme je reprends un code qui n'est pas de moi, je ne sais pas non plus la raison de cette méthode abstract() si ce n'est de détecter les cas ou un héritage aurait du être fait et ne l'ai pas ...
    En fait on va farfouiller dans inspect.getouterframes pour récupérer le nom de la fonction marquée "abstract".

    Il serait plus lisible pour la définition de la méthode abstraite de passer par un "decorator":
    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
    from functools import wraps
    def abstract(f):
        def wrapper(self, *args, **kwds):
            raise NotImplementedError(
                '%s must be implemented in subclass' % f.__name__)
        return wraps(f)(wrapper) 
     
    class A:
        @abstract
        def foo(self):
            pass
     
    class B(A):
        def foo(self):
            print ('foo')
     
    class C(A): pass
     
    B().foo()
    C().foo()
    Voire le module "abc" puisque vous êtes apparemment en 2.7:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import abc
    class A:
        @abc.abstractmethod
        def foo(self):
            raise NotImplementedError('"foo"  must be implemented in subclass')
     
    class B(A):
        def foo(self):
            print ('foo')
     
    class C(A): pass
    B().foo()
    C().foo()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour wiztricks,

    A t'on vraiment besoin d'autre chose que de l'héritage pour cela ?
    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 A:
        def foo(self):
            raise NotImplementedError('"foo"  must be implemented in subclass')
     
     
    class B(A):
        def foo(self):
            print ('foo')
     
     
    class C(A):
        pass
     
     
    B().foo()
    C().foo()
    Cela fonctionne aussi dans l'autre sens
    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 A:
        def __init__(self):
            if not hasattr(self, 'foo'):
                raise NotImplementedError('"foo"  must be implemented in new class')
     
     
    class B(A):
        def foo(self):
            print('foo')
     
     
    class C(A):
        pass
     
     
    b = B()
    b.foo()
    c = C()
    Je me trompe ?

    Merci d'avance.

    @+

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Salut PauseKawa,

    A t'on vraiment besoin d'autre chose que de l'héritage pour cela ?
    Le but étant de définir des méthodes, voire des classes "abstraites", il faut faire un truc "en plus" de l'héritage.

    Et que ce "en plus" soit adapté au but dont le sujet est adapter l'organisation du code permettant d'en gérer la complexité côté nombre de fonctionnalités à réaliser.

    Les machins "abstraits" permettent de définir, documenter l'interface proposée à l'appelant et de la réaliser à façon dans les classes qui "implémentent" l'interface.

    L'interface définira les services:
    - attendus pour ceux qui les utiliseront et
    - a réaliser pour ceux qui devront les coder.
    Et peut permettre de paralléliser les activités de construction des différentes fonctionnalités.

    Si on sort de ce cadre (outil permettant d'organiser la parallélisation des développements - plus de codeurs - et livrer plus vite), la chose n'a pas grand intérêt!

    Une classe héritée suffit amplement pour définir l'interface et pourquoi pas aussi la réaliser? Quelque part pourquoi réaliser un machin "abstract" alors qu'on peut se contenter de...

    Cela rejoint aussi une autre discussion sur pourquoi passer par des classes quand des fonctions suffisent.

    Classes et instances ne sont (souvent) nécessaire que pour "organiser".

    Contrairement à d'autres langages, Python nous permet d'avoir modules et fonctions qui proposent l'organisation de base du langage C avec quelques améliorations.

    Si on doit coder en C un gros machin comme Gtk, ou Cocoa, il va falloir ajouter une couche "objet" basée sur des conventions pour Gtk et sur un compilo Objective-C pour Cocoa.

    Python ayant classes et l'héritage multiple, inutile pour construire "gros" d'inventer classes et héritage qui existent déjà.

    Les machins "abstract" sont là pour permettre de réaliser plus "gros", plus "vite". Le seul intérêt du module "abc" et de proposer une solution prête à l'emploi si besoin. Et c'est "utile" car sans cela, tous les développeurs devaient ré-inventer conventions et ré-écrire du code pour y pallier (comme cela a été fait dans le code présenté ici).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  11. #11
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour wiztricks,

    Merci pour cette réponse complète et argumentée, pour ne pas changer.

    N'ayant pas de 'gros machin' à coder je me contenterais de codes simples du style
    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
    def abstract(f):
        def _d(self, *args, **kwargs):
            raise NotImplementedError('%s must be implemented in %s' \
                                      % (f.__name__, self.__class__.__name__))
        return _d
     
     
    class A:
        @abstract
        def foo(self):
            pass
     
     
    class B(A):
        def foo(self):
            print "foo in B"
     
     
    class C(A):
        pass
     
     
    b = B()
    b.foo()
    c = C()
    c.foo()
    Quelle différence avec functools ?

    @+

  12. #12
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par PauseKawa Voir le message
    Quelle différence avec functools ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        @abstract
        def foo(): pass
    équivaut à:
    Et la variable 'foo' contient une méthode appelée (.__name__) du nom de la fonction créée et retournée par "abstract" ==> ce n'est plus "foo".
    wraps remet les choses dans l'ordre pour que "print" et autres accédant à .__name__ récupèrent le nom attendu.

    N'ayant pas de 'gros machin' à coder je me contenterais de codes simples du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class A:
        @abstract
        def foo(self):
            pass
    Personnellement, je préfère commencer par un simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class A:
        def foo(self):
            raise NotImplementedError('"foo"  must be implemented in subclass')
    L'important est de créer la classe A.
    Cela enrichit le vocabulaire du projet d'un nouvel "objet" en définissant son "contour" (la classe) et ses comportements (la documentation des méthodes). Et çà implique d'aligner le code "derrière" pour en hériter quand c'est "utile".
    C'est structurant puisqu'on partitionne le monde entre les clients de A et les réalisateurs de A.
    C'est une (petite) décision d'architecte (à comparer à "et dieu créa le verbe").

    Le vrai boulot sera de documenter "foo", c'est le texte qui définira le "contrat" de l'interface: les différents acteurs devront "bosser" avec ces "règles".

    Après pour comment dire "oops, z'avez oublié de...", l'important est d'abord "le message". Le "messager" a aussi son importance si on souhaite être "entendu", "compris",...
    Mais sans contexte, cela reste un exercice de "style"...

    Ceci dit, s'il faut ajouter des "signes", le module "abc" existe.
    Dans un contexte professionnel, l'ajout de @abc.abstractmethod sera préférable à l'ajout de "son" @abstract. Les raisons étant "politiques": difficile d'expliquer, pas évident d'appréhender,...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  13. #13
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour wiztricks,

    Je me suis mal exprimé et j'aurais du écrire Quelle différence avec functools dans le cas présent ?

    En effet le code présenté par le PO n'est sûrement pas pour l'utilisateur mais destiné à celui qui vas coder avec.
    A partir de là utiliser functools ou écrire un 'truc' du style
    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
    def abstract(f):
        def _d(self, *args, **kwargs):
            raise NotImplementedError('%s must be implemented in %s'
                                      % (f.__name__, self.__class__.__name__))
        for attr in ('__module__', '__name__', '__doc__'):
            setattr(_d, attr, getattr(f, attr))
        for attr in ('__dict__',):
            getattr(_d, attr).update(getattr(f, attr, {}))
        return _d
     
     
    class A:
        @abstract
        def foo(self):
            """RTFM"""
            pass
     
     
    class B(A):
        def foo(self):
            """B.foo docstring"""
            print "foo in B"
     
     
    class C(A):
        pass
     
     
    b = B()
    print "b.foo.__name__ > ", b.foo.__name__
    print "b.foo.__doc__ > ", b.foo.__doc__
    b.foo()
    c = C()
    print "c.foo.__name__ > ", c.foo.__name__
    print "c.foo.__doc__ > ", c.foo.__doc__
    c.foo()
    Cela n'est il pas 'noyer le poisson' ? Pour moi 'abstract' tel qu'écrit ici n'est qu'un avertissement pour celui qui n'as pas pris le temps de lire la foutue documentation (si existante...). A partir de là 'cacher' le code n'est il pas une mauvaise idée ?

    A la limite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class A:
        def foo(self):
            raise NotImplementedError('"foo"  must be implemented in subclass')
    N'est il pas mieux ?

    Hors contexte vous avez sans doute raison mais ne faut il pas en tenir compte, du contexte ?

    @+ et merci

  14. #14
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Ouch, il y a plusieurs "sujets" là dedans

    Les plus faciles d'abord?

    Citation Envoyé par PauseKawa
    A la limite
    [CODE]class A:
    def foo(self):
    raise NotImplementedError('"foo" must be implemented in subclass')/CODE]
    N'est il pas mieux ?
    A mon sens, c'est par là qu'il faut commencer.
    Le reste étant "signaux et fumée de détresse"

    Citation Envoyé par PauseKawa
    Cela n'est il pas 'noyer le poisson' ? Pour moi 'abstract' tel qu'écrit ici n'est qu'un avertissement pour celui qui n'as pas pris le temps de lire la foutue documentation (si existante...). A partir de là 'cacher' le code n'est il pas une mauvaise idée ?
    L'ajout d'un decorateur est un "signal".
    L'écrire avec "abc.abstracmethod" ne cache pas le code (c'est "open source").

    En effet le code présenté par le PO n'est sûrement pas pour l'utilisateur mais destiné à celui qui vas coder avec
    Exact.

    Le sujet posté montre que le PO a été "confus" par le comportement de ce bout de code dont il a hérité. Initialement son soucis portait sur l'"utilisation d'inspect.getouterframes".

    Il nous a fallu du temps pour comprendre que pouvait être le but d'abstract. Juste parce que "signalisation" et "réalisation" ne sont pas "conventionnelles"
    Cette construction aurait du être "taclée" lors de la revue de code.

    Et si "abc.abstracmethod" existait déjà à cette époque, cette discussion montre qu'il y aurait eu avantage à l'utiliser.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class A:
        def foo(self):
            raise NotImplementedError('"foo" must be implemented in subclass')
    Ce qui nous ramènes à ce souci de toujours vouloir mettre chaque choses dans une 'boite' (désolé pour le plagia) alors que le code ne le 'demande' pas.
    Cette envie de tout 'factoriser' nous mènent à ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	def GenericPanelGet_AllPages(self):
    		abstract()
    Citation Envoyé par wiztricks Voir le message
    Le sujet posté montre que le PO a été "confus" par le comportement de ce bout de code dont il a hérité. Initialement son soucis portait sur l'"utilisation d'inspect.getouterframes".

    Il nous a fallu du temps pour comprendre que pouvait être le but d'abstract. Juste parce que "signalisation" et "réalisation" ne sont pas "conventionnelles"
    Cette construction aurait du être "taclée" lors de la revue de code.

    Et si "abc.abstracmethod" existait déjà à cette époque, cette discussion montre qu'il y aurait eu avantage à l'utiliser.
    Malheureusement inspect.getouterframes est la première chose (avec sys._getframe().f_code.co_name) sur laquelle on tombe sur le web lorsque l'on ne sais pas comment retrouver le nom d'une fonction (caller).
    Je ne pense pas qu'utiliser un outil de debug, ou taper dans la pile, soit la meilleure approche pour du code 'propre' (je vous en reparlerez lorsque j’arriverais a en faire ) dans le cadre du sujet. Un décorateur fait largement l'affaire comme montré dans les divers codes.
    Voyez la confusion portée par ce bout de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def abstract():
        import inspect
        caller = inspect.getouterframes(inspect.currentframe())[1][3]
        raise NotImplementedError(caller + ' must be implemented in subclass')
    Citation Envoyé par wiztricks Voir le message
    L'ajout d'un decorateur est un "signal".
    L'écrire avec "abc.abstracmethod" ne cache pas le code (c'est "open source").
    Dans le sens 'cacher' je comprend
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        for attr in ('__module__', '__name__', '__doc__'):
            setattr(_d, attr, getattr(f, attr))
        for attr in ('__dict__',):
            getattr(_d, attr).update(getattr(f, attr, {}))
    A mon sens inutile ici.

    Edit : Lorsque je dis 'factoriser' c'est que c'était le but mais que l'"on" n'as pas trouver comment récupérer 'caller' autrement.

  16. #16
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par PauseKawa
    Ce qui nous ramènes à ce souci de toujours vouloir mettre chaque choses dans une 'boite' (désolé pour le plagia) alors que le code ne le 'demande' pas.
    Cette envie de tout 'factoriser' nous mènent à ceci
    Ca peut faire sens de ne pas avoir à faire un cut&paste de "raise NotImplementedError('"foo" must be implemented in subclass')" car on oubliera de mettre à jour le "foo" et c'est open pour la confusion.
    Mais si on enlève "foo", le traceback donne l'information à la ligne précédente.

    Un "raise NotImplementedError()" aurait suffit à expliquer au développeur qu'il n'avait pas encore "fini".
    S'ils y ont mis les formes, c'est sans doute pour un problème de communication, de consensus sur la possibilité de partir en week-end ou pas.
    Peut être qu'il y a des "NotImplementedError" pour les fonctionnalités de la V2 que le client n'a pas encore payé?
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  17. #17
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Ca peut faire sens de ne pas avoir à faire un cut&paste de "raise NotImplementedError('"foo" must be implemented in subclass')" car on oubliera de mettre à jour le "foo" et c'est open pour la confusion.
    Mais si on enlève "foo", le traceback donne l'information à la ligne précédente.
    Et même: la réponse suivante (toujours sur la pile) sur le net aurait permis de 'factoriser'...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import sys
     
     
    def abstract(f):
        raise NotImplementedError('%s must be implemented in subclass' % f)
     
     
    class A:
        def foo(self):
            f = sys._getframe().f_code.co_name
            abstract(f)


    Bref: Bon courage awalter1

    @+

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

Discussions similaires

  1. utilisation de imp et inspect
    Par magic.goby dans le forum Général Python
    Réponses: 8
    Dernier message: 12/10/2006, 19h35
  2. utiliser les tag [MFC] [Win32] [.NET] [C++/CLI]
    Par hiko-seijuro dans le forum Visual C++
    Réponses: 8
    Dernier message: 08/06/2005, 15h57
  3. utilisation du meta type ANY
    Par Anonymous dans le forum CORBA
    Réponses: 1
    Dernier message: 15/04/2002, 12h36
  4. [BCB5] Utilisation des Ressources (.res)
    Par Vince78 dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/04/2002, 16h01
  5. Réponses: 2
    Dernier message: 20/03/2002, 23h01

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