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 :

surcharger une methode connue par son nom ?


Sujet :

Python

  1. #1
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut surcharger une methode connue par son nom ?
    Bonjour,

    Comment faire pour surcharger une méthode dont on ne connait que le nom ?

    Cette question m'est apparue sur l'exemple suivant:

    Je cherche à décorer une classe de sorte qu'un point d'arret soit rencontré lorsqu'une certaine méthode est appelée. Mon problème vient de ce que je ne connais que le nom de la methode (method_name dans le code).

    L'exception
    TypeError: 'dictproxy' object does not support item assignment
    est levée par la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _watch.__dict__[method_name]= _watch._watched_method
    c'est à dire au moment ou j'essaye d'assigner via son nom la méthode avec point d'arret à la nouvelle classe.

    Est-ce le fait que la classe _watch soit intérieure à une fonction qui fait que sont __dict__ est un dictproxy ? Comment puis-je faire ?

    Merci d'avance


    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
     
    def any_args(self,*a,**k): return True
     
    def watch_call(method_name,arg_test= any_args):
        def make_watcher(obj):
            class _watch(obj):
                def __init__(self,*a,**k): obj.__init__(self,*a,**k)
                def _watched_method(self,*a,**k):
                    if arg_test(self,*a,**k):
                        WATCH_DEBUG= None # POINT D'ARRET ICI
                    return obj.__dict__["method_name"](self,*a ,**k)
            _watch.__dict__[method_name]= _watch._watched_method
            return _watch
        return make_watcher
     
    if __name__== "__main__":
        l= watch_call("append")(list)()
        l.append(1) # cet appel doit passer par le point d'arret
    (arg_test permet juste de ne passer sur le point d'arret que lorsque les arguments de la méthodes vérifient une condition donnée)

  2. #2
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Salut,

    En utilisant setattr, ça marche (au passage, ’y avait aussi une erreur ligne 11… Du coup, j’en ai profité pour là aussi utiliser getattr, c’est mieux comme ça, amha*! )*:

    Code python : 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
    def any_args(self,*a,**k): return True
     
    def watch_call(method_name,arg_test= any_args):
        def make_watcher(obj):
            class _watch(obj):
                def __init__(self,*a,**k): obj.__init__(self,*a,**k)
                def _watched_method(self,*a,**k):
                    if arg_test(self,*a,**k):
                        print("point d’arrêt*!")
                        WATCH_DEBUG = None # POINT D'ARRET ICI
                    return getattr(obj, method_name)(self,*a ,**k)
            setattr(_watch, method_name, _watch._watched_method)
            return _watch
        return make_watcher
     
    if __name__== "__main__":
        l = watch_call("append")(list)()
        l.append(1) # cet appel doit passer par le point d'arret


  3. #3
    Expert confirmé 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
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> class Foo(object):
    ...     pass
    ... 
    >>> Foo.__dict__.items()
    [('__dict__', <attribute '__dict__' of 'Foo' objects>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Foo' objects>), ('__doc__', None)]
    >>> Foo.__dict__['foo'] = 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'dict_proxy' object does not support item assignment
    >>> f = Foo()
    >>> f.__dict__['foo'] = 1
    >>> f.__dict__.items()
    dict_items([('foo', 1)])
    @+
    Merci d'utiliser le forum pour les questions techniques.

  4. #4
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut ok setattr()
    Merci à tous les 2.

    Je précise tout de même 2 choses qui diffèrent chez moi (je suis sous py 2.6, tandis que vous avez l'air d'etre en 3.x)

    1/ return obj.__dict__["method_name"](self,*a ,**k) marche sans avoir besoin de getattr

    2/ Dans l'exemple de PauseKawa, Foo.__dict__['foo'] = 1 ne lève pas d'erreur, lorsque la classe n'est pas définie dans une fonction

    Dernière petite question, je trouve l'instruction un peu lourde
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    watch_call("__setitem__",lambda s,*a,**k: a[0]== "a" )(dict)()
    Pas possible de faire plus court ? avec un @ bien placé (et en une seule ligne) ?

  5. #5
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Citation Envoyé par VV33D Voir le message
    1/ return obj.__dict__["method_name"](self,*a ,**k) marche sans avoir besoin de getattr
    Ça, ça m’étonnerait vraiment, mais alors vraiment beaucoup… return obj.__dict__[method_name](self,*a ,**k), par contre, doit effectivement marcher (y compris en py3k)*!

    Citation Envoyé par VV33D Voir le message
    Dernière petite question, je trouve l'instruction un peu lourde
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    watch_call("__setitem__",lambda s,*a,**k: a[0]== "a" )(dict)()
    Pas possible de faire plus court ? avec un @ bien placé (et en une seule ligne) ?
    Ben vi, c’est un peu lourd… Mais je ne vois pas trop comment un decorator pourrait t’aider, là. Par contre, tu peux nettement alléger ton code en supprimant un niveau intermédiaire, apparemment totalement inutile*?

    Code python : 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
    def any_args(self,*a,**k): return True
     
    def watch_call(obj, method_name, arg_test= any_args):
        class _watch(obj):
            def __init__(self,*a,**k): obj.__init__(self,*a,**k)
            def _watched_method(self,*a,**k):
                if arg_test(self,*a,**k):
                    print("point d’arrêt (a[0] = %s)*!" % a[0])
                    WATCH_DEBUG = None # POINT D'ARRET ICI
                return getattr(obj,method_name)(self,*a ,**k)
        setattr(_watch, method_name, _watch._watched_method)
        return _watch
     
    if __name__== "__main__":
        l = watch_call(list, "append", lambda s,*a,**k: a[0]== "a")()
        l.append("a") # cet appel doit passer par le point d'arret
        l.append("b") # cet appel ne doit pas passer par le point d'arret


  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Bonsoir,

    quelques simplifications supplémentaires (et j'ai renommé obj en cls; c'est plus clair).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def watch_call(cls, method_name, arg_test=lambda *a,**k:True):
        def _watched_method(self,*a,**k):
            if arg_test(self,*a,**k):
                print("point d’arrêt (a[0] = %s)!" % a[0])
                WATCH_DEBUG = None # POINT D'ARRET ICI
            return getattr(cls,method_name)(self, *a ,**k)
        return type(cls.__name__, (cls,), {method_name: _watched_method})
     
    if __name__== "__main__":
        l = watch_call(list, "append", lambda self,x: x == "a")()
        l.append("a") # cet appel doit passer par le point d'arret
        l.append("b") # cet appel ne doit pas passer par le point d'arret

  7. #7
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Bonne idée l’utilisation de type(), dividee, j’y aurais pas pensé…

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

Discussions similaires

  1. [POI] Appeler une cellule par son nom
    Par Galak extra dans le forum Documents
    Réponses: 9
    Dernier message: 17/06/2008, 14h33
  2. [Conception] invoquer une methode par son nom
    Par orelero dans le forum Général Java
    Réponses: 13
    Dernier message: 24/10/2006, 11h18
  3. [VB6] Appeler une procedure par son nom.
    Par kenn dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 24/05/2006, 09h29
  4. Accéder à une propriété par son nom
    Par Neilos dans le forum C++Builder
    Réponses: 5
    Dernier message: 22/09/2005, 21h34

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