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 :

exécuter une fonction décorée dans un processus (de multiprocessing)


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2019
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Pays-Bas

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2019
    Messages : 17
    Par défaut exécuter une fonction décorée dans un processus (de multiprocessing)
    Bonjour,

    J'essaie de lancer un processus (en python 3.5) qui devrait exécuter une fonction décorée, mais ça ne marche pas.
    Voici le message d'erreur qui s'affiche:

    AttributeError: Can't pickle local object 'deco.<locals>.fonctionDecoree'
    La fonction décorée semble donc ne plus être une fonction à proprement parler. Or, en dehors de mon processus elle se comporte tout à fait comme une fonction.

    Voici un bout de code ayant pour but de résumer la situation. Si vous l'exécuter une fois avec "@deco" activé, et une fois avec "@deco" en commentaire, ça devrait devenir clair.

    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
     
    from multiprocessing import Process
     
    def deco(fonction):
        def fonctionDecoree():
            print("La fonction qu'on appelle a été décorée.")
            fonction()
        return fonctionDecoree
     
    @deco
    def fonctionTest():
        print("On appelle la fonction d'essai.")
     
    if __name__ == "__main__":
     
        print("Le type de la fonction d'essai:")
        print(type(fonctionTest))
        print("--------------------------------\n")
     
        fonctionTest()
        print("--------------------------------\n")
     
        print("Démarrage d'un processus exécutant la fonction:")
        p = Process(target=fonctionTest)
        p.start() # La méthode qui fait planter le code quand @deco est activé.
        print("Le processus a bien été démarré.")
    Pour moi cette situation n'est pas tellement un problème, mais plutôt un comportement inattendu que j'ai rencontré un peu par hasard, en faisant des essais.
    Pourtant j'aimerais savoir d'où ça vient, parce que j'aime beaucoup utiliser les décorateurs, et ce n'est pas la première fois que leur étrange comportement me prend au dépourvu. Merci d'avance de m'aider.

  2. #2
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut,

    Il faut "emballer" ta fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    from functools import wraps
     
    def deco(fonction):
        @wraps(fonction)
        def fonctionDecoree():
            print("La fonction qu'on appelle a été décorée.")
            return fonction()
        return fonctionDecoree
     
    @deco
    def fonctionTest():
        print("On appelle la fonction d'essai.")

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 828
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 828
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Bram van Dam Voir le message
    J'essaie de lancer un processus (en python 3.5) qui devrait exécuter une fonction décorée, mais ça ne marche pas.
    Chez-moi, avec P3.4.2, ça marche bien...

    Citation Envoyé par Bram van Dam Voir le message
    Voici un bout de code ayant pour but de résumer la situation. Si vous l'exécuter une fois avec "@deco" activé, et une fois avec "@deco" en commentaire, ça devrait devenir clair.
    Désolé, j'ai fait deux essais que j'ai redirigé vers deux fichiers. Voici le résultat (à gauche avec, et à droite sans)

    Nom : VirtualBox_Debian8_64b_16_03_2019_10_03_27.png
Affichages : 188
Taille : 76,1 Ko
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Membre chevronné
    Homme Profil pro
    Développeur banc de test
    Inscrit en
    Mai 2014
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur banc de test
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2014
    Messages : 199
    Par défaut
    Bonjour,

    L'erreur "Can't pickle local object" vient du fait que l'objet fonctionTest ne peut pas être sérialisé avec pickle, méthode utilisée par multiprocessing (pour permettre des échange entre processus si j'ai bien compris).

    Le fait de passer le décorateur sur la fonctionTest change les attributs qui caractérisent cette fonction.

    Par exemple fonctionTest.__name__ va porter le nom "fonctionDecoree"

    En utilisant wraps de functools on permet d'attribuer à la nouvelle fonction décorée ses attributs d'origine.

    Citation Envoyé par YCL-1 Voir le message
    En regardant dans la librairie \Lib\functools.py

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    # update_wrapper() and wraps() are tools to help write
    # wrapper functions that can handle naive introspection
     
    WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                           '__annotations__')
    Et apparemment multiprocessing utilise l'attribut __qualname__ pour vérifier que les objets passés sont pickable : PEP 3154 -- Pickle protocol version 4


    PEP 395 -- Qualified Names for Modules


    On peut corriger le problème soit en utilisant wraps comme dans la solution de VinsS, qui a l'avantage de copier tous les attributs importants, comme __doc__ par exemple.
    Soit juste de copier __qualname__.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def deco(fonction):
        def fonctionDecoree():
            print("La fonction qu'on appelle a été décorée.")
            fonction()
        fonctionDecoree.__qualname__ = fonction.__qualname__
        return fonctionDecoree

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2019
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Pays-Bas

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2019
    Messages : 17
    Par défaut
    Merci à tous de m'avoir aidé. Vos réponses se complètent bien, surtout celle de YCL-1 m'a été utile.
    Je peux continuer maintenant.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 717
    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 717
    Par défaut
    Salut,

    Citation Envoyé par Sve@r Voir le message
    Désolé, j'ai fait deux essais que j'ai redirigé vers deux fichiers. Voici le résultat (à gauche avec, et à droite sans)
    Sur Linux, les autres process sont créés via fork, sous Windows, on recopie "à la main" l'état des objets via pickle.

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

  7. #7
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 060
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 060
    Par défaut
    On aurait même pu s'économiser quelques lignes et une importation de module

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def deco(fonction):    
        def fonctionDecoree():
            print("La fonction qu'on appelle a été décorée.")
            return fonction()
        return fonctionDecoree
     
    @deco
    def fonctionTest():
        print("On appelle la fonction d'essai.")

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

Discussions similaires

  1. [MEX] Exécuter une fonction Fortran dans MATLAB
    Par salloum dans le forum MATLAB
    Réponses: 11
    Dernier message: 04/05/2011, 09h48
  2. Exécuter une fonction JS dans un HTML inséré par un <object>
    Par GRAF dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 22/03/2011, 21h23
  3. Exécuter une fonction contenue dans un string
    Par ninikkhuet dans le forum Langage
    Réponses: 5
    Dernier message: 06/05/2010, 15h18
  4. Réponses: 2
    Dernier message: 28/11/2007, 17h49
  5. Exécuter une fonction PL/SQL dans SQL*PLUS
    Par soumou dans le forum PL/SQL
    Réponses: 5
    Dernier message: 03/11/2006, 00h07

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