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 :

Métaclasses vs décorateur


Sujet :

Python

  1. #1
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut Métaclasses vs décorateur
    Bonjour,

    Je suis en train de tester 2 solutions pour faire un Singleton : par métaclasse, et par décorateur.

    Si la métaclasse fonctionne bien, j'ai un truc bizarre avec le décorateur :

    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
    def singleton(cls):
        instances = {}
        def getinstance():
            if cls not in instances:
                instances[cls] = cls()
            return instances[cls]
        return getinstance
     
    @singleton
    class MyClass(object):
        def __init__(self):
            super(MyClass, self).__init__()
            self.a = 1
     
    MyClass()
    car j'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Traceback (most recent call last):
      File "deco.py", line 17, in <module>
        MyClass()
      File "deco.py", line 5, in getinstance
        instances[cls] = cls()
      File "deco.py", line 13, in __init__
        super(MyClass, self).__init__()
    TypeError: must be type, not function
    Quelqu'un peut-il m'expliquer ce qui se passe, exactement ? Je n'arrive pas à suivre le cheminement de python lors de la création/initialisation de la classe... J'imagine qu'une fois compris ça, la réponse coule se source

    Merci d'avance.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Salut,
    Citation Envoyé par fma38 Voir le message
    Quelqu'un peut-il m'expliquer ce qui se passe, exactement ?
    Le message d'erreur est explicite: vous remplacez une classe par une fonction et super n'aime pas.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 062
    Par défaut
    On est bien d'accord sur le fait que tu veux un singleton pour n'avoir à créer qu'une seule instance ?

    C'est rare ce genre d'utilisation, j'aimerais bien savoir pour quel besoin exactement.

    Bref, le singleton le plus pythonique (que je connaisse) est celui-ci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Singleton(object):
        def __new__(cls, *args, **kwargs):
            if '_inst' not in vars(cls):
                cls._inst = type.__new__(cls, *args, **kwargs)
            return cls._inst
    Source : Jürgen Hermann

    Bonne continuation...

  4. #4
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Le message d'erreur est explicite: vous remplacez une classe par une fonction et super n'aime pas.
    Pourquoi 'je emplace' ? C'est là où je ne suis pas sûr de piger. Certes, le décorateur encapsule la classe dans une fonction, mais cela reste une classe, non ? Où alors cela veut dire que même les appel depuis l'intérieur voit la fonction au lieu de la classe ?

  5. #5
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    On est bien d'accord sur le fait que tu veux un singleton pour n'avoir à créer qu'une seule instance ?
    Yep, c'est ça.

    C'est rare ce genre d'utilisation, j'aimerais bien savoir pour quel besoin exactement.
    J'ai 2-3 objets qui sont des services globaux dont je veux disposer sans avoir besoin de les passer en paramètre à tout va. Genre le logger.

    Bref, le singleton le plus pythonique (que je connaisse) est celui-ci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Singleton(object):
        def __new__(cls, *args, **kwargs):
            if '_inst' not in vars(cls):
                cls._inst = type.__new__(cls, *args, **kwargs)
            return cls._inst
    Source : Jürgen Hermann
    Y'a effectivement plein de façons de faire : je le fais aussi via une variable de module. Sinon, au boulot, dans notre gros code, on utilise plutôt des Borgs que des Singleton.

    Mais bon, je ne veux pas rentrer dans le débat de l'un ou de l'autre utilisation ; c'était juste pour comprendre ce qui se passait avec le décorateur (pas spécifique au Singleton, d'ailleurs).

    Merci.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Pourquoi 'je emplace' ? C'est là où je ne suis pas sûr de piger. Certes, le décorateur encapsule la classe dans une fonction, mais cela reste une classe, non ? Où alors cela veut dire que même les appel depuis l'intérieur voit la fonction au lieu de la classe ?
    C'est pourtant ce que dit le message d'erreur.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    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 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Oui, super n'a pas l'air de supporter une classe directement issue de object, et je ne suis pas sûr que l'appel de __init__ de object soit nécessaire.

    Sinon, les solutions du singleton avec décorateur sont intéressantes. Voilà comment je le coderais (Python 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
    14
    15
    16
    17
    18
    def singleton(fonc):
        instances = []
        def appelfonc(*args, **kwargs):
            if fonc not in instances:    
                instances.append(fonc)
                return fonc(*args, **kwargs)
            else:
                raise ValueError, ("erreur: tentative 2e instance de " + fonc.__name__)
        return appelfonc
     
    @singleton
    class MyClass(object):
        def __init__(self):
            object.__init__(self)
            self.a = 1
     
    x = MyClass()
    y = MyClass() #<=== erreur: tentative de création d'une 2ème instance
    Le "raise" suggère que l'appelant gère l'exception.

    On peut aussi vouloir limiter la création des instances à un certain nombre, par exemple 2 ou 3. Dans ce cas, on peut utiliser un décorateur qui accepte un paramètre:

    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
    def singleton(max=1):
        instances = [] 
        def _decorateur(fonc):
            def appelfonc(*args, **kwargs):
                if instances.count(fonc)<max:    
                    instances.append(fonc)
                    return fonc(*args, **kwargs)
                else:
                    raise ValueError, ("erreur: tentative 2e instance de " + fonc.__name__)
            return appelfonc
        return _decorateur
     
    @singleton(2)
    class MyClass(object):
        def __init__(self):
            object.__init__(self)
            self.a = 1
     
    x = MyClass()
    y = MyClass()
    z = MyClass() # <=== erreur: tentative de création d'une 3ème instance
    Attention: dans ce décorateur avec paramètre, il faut toujours mettre les parenthèses, même si on laisse la valeur par défaut => @singleton().

  8. #8
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Oui, super n'a pas l'air de supporter une classe directement issue de object, et je ne suis pas sûr que l'appel de __init__ de object soit nécessaire.
    C'est le fait que le premier paramètre soir une fonction et non une classe qui l'embète...

    Et si, l'appel à super() est important lorsqu'on hérite de object ; sans lui, la résolution des appels lors de l'héritage multiple ne suit plus celle du new-style, justement ! Entre autres...

    Sinon, les solutions du singleton avec décorateur sont intéressantes. Voilà comment je le coderais (Python 2.7):
    Merci pour ces exemples !

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Salut,
    Citation Envoyé par fma38 Voir le message
    Et si, l'appel à super() est important lorsqu'on hérite de object ; sans lui, la résolution des appels lors de l'héritage multiple ne suit plus celle du new-style, justement ! Entre autres...
    Quel est le sens d'un singleton dans un héritage multiple? voire d'un héritage simple? Vous gérez comment le threading pour garantir l’unicité de l'instance du Singleton?
    Quels sont les avantages inconvénient de l'utilisation d'un module (comme singleton) par rapport a des solutions autres?

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

  10. #10
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Quel est le sens d'un singleton dans un héritage multiple? voire d'un héritage simple? Vous gérez comment le threading pour garantir l’unicité de l'instance du Singleton?
    Ma réponse concernant l'appel à super() était en fait générique ; effectivement, dans le cas présent, ça peut se discuter. Mais bon, hériter de objet et ne pas avoir son comportement n'est à mon avis pas une bonne idée. C'est un coup à se retrouver face à des trucs bizarres (le problème de résolution de nom n'est sans doute qu'un des problèmes potentiels...).

    Quant à la gestion en multithreading, je n'y ai jamais été confronté, puisque j'utilisais jusqu'à présent uniquement des Borg. Et ça, ça fonctionne très bien.

    Quels sont les avantages inconvénient de l'utilisation d'un module (comme singleton) par rapport a des solutions autres?
    Jamais pesé le pour et le contre, à vrai dire. L'utilisation de la variable de module m'avait été suggéré par un formateur python très compétent. Là encore, je n'ai jamais pris cette implémentation en défaut, même en multithreading !

  11. #11
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 062
    Par défaut
    L'héritage de Singleton n'est pas un cas simple, et comme le dis Wiztrick, chaque sous classe directe ou indirecte recevra une instance distincte. Ce qui en d'autres termes viole la contrainte une seule instance.

    Cette problématique peut être gênante et dans ce cas, il serait souhaitable d'utiliser l'idiome Borg.

    Edit: Juste un petit rajout pour parler du choix des motifs Singleton ou Borg, qui très souvent, si on y réfléchi bien, n'a pas besoin d'être utilisé.

    En python, on peut faire très simple et les éviter en faisant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class A(object):
        def __init__(self):
            # blabla
     
    A = A()
    Dans le cas ci-dessus A est la seule instance de sa propre classe.

    Bonne continuation...

  12. #12
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Ma réponse concernant l'appel à super() était en fait générique ; effectivement, dans le cas présent, ça peut se discuter.
    ...
    Quant à la gestion en multithreading, je n'y ai jamais été confronté, puisque j'utilisais jusqu'à présent uniquement des Borg. Et ça, ça fonctionne très bien.
    Un pattern "monostate" (aka. Borg) a d'autres cas d'utilisations que "singleton". Ce sont ces cas d'utilisations qui rendent "glissantes" toutes considérations "génériques": super() dans le cas d'un singleton est "a problème" que n'aura pas "monostate".

    Jamais pesé le pour et le contre, à vrai dire. L'utilisation de la variable de module m'avait été suggéré par un formateur python très compétent. Là encore, je n'ai jamais pris cette implémentation en défaut, même en multithreading !
    Il est vrai que l'informatique ressemble parfois a des recettes de cuisines qu'on se refile d'un forum a l'autre... mais c'est un peu plus complique.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  13. #13
    Membre confirmé Avatar de fma38
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 119
    Par défaut
    En fait, je me pose la question de savoir dans quel cas on a réellement besoin d'un vrai Singleton ?

  14. #14
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 062
    Par défaut
    Je n'ai pas répondu à cette question le post précédent ?

  15. #15
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    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 738
    Par défaut
    Salut,
    Citation Envoyé par fred1599 Voir le message
    Edit: Juste un petit rajout pour parler du choix des motifs Singleton ou Borg, qui très souvent, si on y réfléchi bien, n'a pas besoin d'être utilisé.

    En python, on peut faire très simple et les éviter en faisant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class A(object):
        def __init__(self):
            # blabla
     
    A = A()
    Dans le cas ci-dessus A est la seule instance de sa propre classe.
    Ah ben si on revient aux variables globales, effectivement, pas la peine de...
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [DisplayTag] Décorateur display tag
    Par newmar dans le forum Taglibs
    Réponses: 5
    Dernier message: 18/06/2008, 16h19
  2. Utilité des décorateurs en JAVA
    Par specsy dans le forum Général Java
    Réponses: 5
    Dernier message: 15/04/2008, 17h32
  3. Réponses: 3
    Dernier message: 07/12/2007, 11h35
  4. [Décorateur] Desassembler des Décorateurs
    Par NiamorH dans le forum Design Patterns
    Réponses: 3
    Dernier message: 28/10/2007, 09h29

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