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 :

tester si fonction avec return a été exécutée


Sujet :

Python

  1. #21
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 43
    Points : 67
    Points
    67
    Par défaut
    Est-ce qu'une simple mise en cache des résultats de la fonction ne suffirait pas ?

    Toujours avec un décorateur :
    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
    19
    20
    21
    22
    23
     
    def cache(funct):
        def f(*args, **kwargs):
            key = (args, tuple(kwargs.items()))
            try:
                return funct._cache[key]
            except KeyError:
                r = funct._cache[key] = funct(*args, **kwargs)
                return r
        if not hasattr(funct, "_cache"):
            funct._cache = dict()
        return f
     
    @cache
    def test():
        # ...
     
    if hasattr(test, "_cache"):
        print("La fonction a déjà été appelée !")
        # les arguments qui lui ont été passé : test._cache.keys()
        # les resultats qu'elle a renvoyé : test._cache.values()
    else:
        print("La fonction n'a jamais été appelée !")

  2. #22
    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
    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
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    #
    #
    def cache(funct):
        def f(*args, **kwargs):
            key = (args, tuple(kwargs.items()))
            try:
                return funct._cache[key]
            except KeyError:
                r = funct._cache[key] = funct(*args, **kwargs)
                return r
        if not hasattr(funct, "_cache"):
            funct._cache = dict()
        return f
     
    @cache
    def Foo(a, b):
        return a*b
     
    Foo(1, 2)
    Foo(2, 2)
    Foo(4, 2)
     
    if hasattr(Foo, "_cache"):
        print("La fonction a déjà été appelée !")
        # les arguments qui lui ont été passé : test._cache.keys()
        # les resultats qu'elle a renvoyé : test._cache.values()
    else:
        print("La fonction n'a jamais été appelée !")
    Output
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    La fonction n'a jamais été appelée !

  3. #23
    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
    tyrtamos, je pense que tu es passé à côté de qqch dans ton décorateur (et PauseKawa a suivi ^^):

    Par exemple, dans le code de tyrtamos, on peut écrire:
    au lieu de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print mondecorateur.adrinst['test'].resultats
    Le dictionnaire-attribut-de-classe, il ne sert à rien

  4. #24
    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
    Bonjour dividee,

    Citation Envoyé par dividee Voir le message
    tyrtamos, je pense que tu es passé à côté de qqch dans ton décorateur (et PauseKawa a suivi ^^):
    Le dictionnaire-attribut-de-classe, il ne sert à rien
    Ici ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class interceptor(object):
        def __init__(self, fonc=None, d={}):
            self.fonc = fonc
            self.d = d
    ?

  5. #25
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    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 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Bonjour dividee,

    Merci pour l'astuce, mais je n'aurais jamais écrit ça par moi-même: pour moi, dans mon code, test est une fonction et non une classe.

    Donc, Python affecte au nom de la fonction décorée l'adresse de l'instance de classe du décorateur?

    Waou...

    Peux-tu en dire un peu plus? Merci!

    Tyrtamos

  6. #26
    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
    @PauseKawa:
    Oui; tu as utilisé une valeur par défaut au lieu d'un attribut de classe mais l'effet est similaire. Tu pourrais directement appeler Foo.getvalues sans avoir besoin d'un dictionnaire commun à toutes les instances...

    @tyrtamos:
    Citation Envoyé par tyrtamos Voir le message
    Donc, Python affecte au nom de la fonction décorée l'adresse de l'instance de classe du décorateur?

    Waou...

    Peux-tu en dire un peu plus? Merci!
    Ben oui, en fait le fonctionnement d'un décorateur c'est très simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    @deco
    def test():
        ...
    est équivalent à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def test():
        ...
    test = deco(test)
    Donc si deco est une classe, test sera une instance de la classe.

    [edit]
    Je trouve intéressant qu'un décorateur soit un "sucre syntaxique" aussi simple (on peut facilement s'en passer), mais qu'il encourage une façon différente de résoudre certains problèmes.

  7. #27
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    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 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Je connaissais l'équivalence, mais je prenais ça pour un raccourci pédagogique, et je n'en avais pas déduit cette conséquence.

    Chouette, ça va simplifier mon code!

    Merci dividee.

    EDIT: Nouvelle version:

    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
    import functools
     
    class mondecorateur(object):
        """ decorateur qui stocke les résultats d'appels des fonctions décorées """
        def __init__(self, fonc):
            self.fonc = fonc
            functools.wraps(fonc)(self)
            self.nbappels = 0
            self.resultats = {}
        def __call__(self, *args, **kwargs):
            """ méthode appelée à chaque appel de la fonction décorée """
            result = self.fonc(*args, **kwargs)
            self.nbappels += 1
            self.resultats[self.nbappels] = result
            return result
    Et on récupère, bien sur les résultats avec:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    print test.nbappels
    print test.resultats

  8. #28
    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
    Citation Envoyé par tyrtamos Voir le message
    Donc, Python affecte au nom de la fonction décorée l'adresse de l'instance de classe du décorateur?
    Oui. Tu en as un exemple avec le code PsycoPy: La fonction Foo n'a jamais l'attribut _cache (faire des print).

    Pour ma défense j'étais parti sur du code 'simple' (utiliser la fonction) plutôt que de passer par des décorateurs. (Pas convainquent ? Ok -->[])

  9. #29
    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
    Bonjour,

    Citation Envoyé par tyrtamos Voir le message
    Et on récupère, bien sur les résultats avec:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    print test.nbappels
    print test.resultats
    Il faut conditionner pour éviter l'AttributeError.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if hasattr(test, "nbappels"):
        print(test.nbappels)
    @+

  10. #30
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    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 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Bonjour PauseKawa,

    Citation Envoyé par PauseKawa Voir le message
    Il faut conditionner pour éviter l'AttributeError
    Et pourquoi aurait-on un AttributeError???

  11. #31
    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
    Bonjour,

    Je ne sais pas si je dois le dire.. Bon... Ok.

    Ce matin j'ai tester le décorateur avec trois fonctions* (Foo, Foo1 et Foo2).
    Divers appels pour Foo et Foo1 et pas pour Foo2.
    A chaque test j'avais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        print(Foo2.nbappels)
    AttributeError: 'function' object has no attribute 'nbappels'
    Incompréhensible...
    Surtout que j'ai tester pour comprendre au bureau et que sur mon poste Windows cela fonctionne (et ne peux que fonctionner...)
    Je dois avouer que j'ai fais chauffer mon mono neurone.
    Là je viens de rentrer du taf et... J'avais oublier le décorateur pour Foo2.
    Je vous laisse. Je cherche sur internet un aller simple low cost pour le tibet. Histoire de me faire oublier quelques temps...

    *Note perso : Jamais avant le café de préférence.

Discussions similaires

  1. Fonction avec getopts ne s'exécute qu'une seule fois
    Par yzoug dans le forum Shell et commandes GNU
    Réponses: 9
    Dernier message: 02/03/2015, 12h44
  2. Fonction avec return table
    Par Aethia dans le forum Sybase
    Réponses: 6
    Dernier message: 11/12/2013, 18h39
  3. Fonction avec un return
    Par baleiney dans le forum Langage
    Réponses: 2
    Dernier message: 03/01/2008, 23h27
  4. Exécution de deux fonction avec ie
    Par musicann dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 15/06/2007, 14h25
  5. Fonction avec divers return possibles
    Par inddzen dans le forum C++
    Réponses: 11
    Dernier message: 28/02/2007, 23h08

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