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 :

metaclasse pour ajouter un context manager


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 metaclasse pour ajouter un context manager
    Bonjour,

    J'ai cette classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A:
        with some_context():
            x = f(0)
            y = f(1)
    Pour laquelle il est très important que f() soit appelée au sein du context manager ouvert.

    Je voudrais automatiser ce with à l'aide d'une métaclasse, de sorte que ceci soit équivalent:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class B(meta=M):    
        x = f(0)
        y = f(1)
    Si j'essaie de décorer B, c'est trop tard : ses attributs x,y ont été évalués, et f() a été appelée sans contexte.

    Est-ce qu'une métaclasse me donne un hook suffisement tôt (avant que f() soit appelée) pour ajouter mon contexte ? Il faudrait que cela ait lieu avant que les attributs de classe soient construits !

    Merci d'avance !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par shaiHulud Voir le message
    Est-ce qu'une métaclasse me donne un hook suffisement tôt (avant que f() soit appelée) pour ajouter mon contexte ?
    non car, si vous aviez un peu regardé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> class A(type):
    ...     def __new__(cls, name, bases, dict):
    ...         print (dict)
    ...         return super().__new__(cls, name, bases, dict)
    ...
    >>> class B(metaclass=A):
    ...     x = 0
    ...     y = 1
    ...
    {'y': 1, '__module__': '__main__', '__qualname__': 'B', 'x': 0}
    >>>
    x et y sont des attributs et se retrouvent dans le dict passé dans le __new__ de la metaclass (et plus tôt n'est pas possible).

    Par contre, rien ne vous empêche d'écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A:
          x = None
          y = None
     
    with ...:
          A.x = f(0)
          A.y = f(1)
    ou plus concis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    with ...:
          A = type('A', (), { x = f(0), y = f(1) }
    Donc pas besoin des metaclass.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Bonjour,

    Citation Envoyé par wiztricks Voir le message
    x et y sont des attributs et se retrouvent dans le dict passé dans le __new__ de la metaclass (et plus tôt n'est pas possible).
    En fait, il existe un hook __prepare__ qui, quand il est présent, est appelé avant le __new__ de la métaclasse. Il est même appelé avant les évaluations de x et de y.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    En fait, il existe un hook __prepare__ qui, quand il est présent, est appelé avant le __new__ de la métaclasse. Il est même appelé avant les évaluations de x et de y.
    Ah oui, je l'avais oublié celui là mais difficile voire impossible à utiliser dans ce contexte: on peux toujours retourner un dictionnaire avec les bonnes valeurs de x et y mais elles seront ré-initialisées ensuite.
    La seule solution serait d'avoir une sorte de typage, i.e une classe Toto qui prenne f et ses arguments en paramètres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class B(metaclass=A):
             x = Toto(f, 0)
             y = Toto(f, 1)
    puis dans l'__init__ de la metaclass on récupère les attributs associés à des instances de Toto pour les ré-initialiser.

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

  5. #5
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    On pourrait aussi faire le travail de the_context.__enter__ dans __prepare__(metacls, name, bases, **kwds) et celui de the_context.__exit__ dans le __new__(cls, name, bases, namespace, **kwds) de la métaclasse. the_context pourrait faire partie des arguments de kwds.

    Ainsi, x = f(0) et y = f(0) seraient bien exécutés entre ce que ferait the_context.__enter__ et ce que ferait the_context.__exit__.

    Mais avant de s'embarquer dans une solution compliquée, il faudrait que l'on connaisse le contexte pour savoir si c'est pertinent. shaiHulud, à quoi correspondent f et some_context() ?

  6. #6
    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
    Tout d'abord merci beaucoup pour vos réponses.

    J'essaie d'automatiser la création de namespace en tensorflow. L'exemple complet serait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A:
        with tensorflow.name_scope("A"):
            x = tensorflow.Variable(0, name="x")
            y = tensorflow.Variable(1, name="y")
    Lorsque le contexte tensorflow.name_scope est ouvert, le nom des variables sont changés, par example ici de "x" en "A/x".

    Mon but est que l'utilisateur puisse écrire une classe A sans avoir à s'occuper des name_scope. Je veux automatiser ces name_scope avec une métaclasse (ou autre, décorateur ...).

    Le contexte que j'utiliserai au final wrappera - mais sera un peu plus compliqué que - tensorflow.name_scope : je veux un namescope pour les méthodes/attributes de classe, un autre par instance, et enfin un namescope imbriqué "instance_2/foo_1" pour chaque appel à chaque méthode foo. Je suis capable pour l'instant de gérer tous ces namescope par décoration, sauf celui des attributs de classe.


    @ wiztricks: avec des factory (Toto), un decorateur suffirait. Mais je ne veux pas que l'utilisateur codant la classe A soit autant affecté. Il doit écrire du code tensorflow de base :
    x = tensorflow.Variable(0, name="x") et non pas x = Factory(tensorflow.Variable, 0, name="x").

    @ Pyramidev: j'étais justement en train d'essayer ta suggestion. Ca semble fonctionner, mais j'ai quelques questions:
    * Ou assigner le contexte ouvert par __prepare__ pour être récupérable dans __new__. Je le mets dans la metaclasse, mais si plusieurs classes utilisent la même, il y aura des interférences ?
    * A plus forte raison dans le cas threadé.
    * Comment gérer proprement les exceptions ?

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    """ Some mocking """
    class struct: pass
    class _name_scope(object):
        def __init__(self, *a): self.a = a
        def __enter__(self):
            print("in _name_scope", self.a)
            return self
        def __exit__(self, *b):
            print("out _name_scope", self.a)
            return self
    def _Variable(*a, **k):
        print("Variable", a, k)
        return a[0]
     
    tf = struct() #py3 mocking
    tf.name_scope = _name_scope
    tf.Variable = _Variable
    tf.int32 = None
     
    class Meta_(type):                    
        @classmethod # Py3 only ...
        def __prepare__(metacls, name, bases):
            #print("prepare", metacls, name, bases) #prepare <class '__main__.Meta_'> TestMeta ()        
            metacls.opened = tf.name_scope("TestMeta").__enter__()
            return {}        
     
        def __new__(cls, name, bases, classdict):
           # print("new", cls, name, bases, classdict)
            # new <class '__main__.Meta_'> TestMeta () {'cm': <__main__._name_scope object at 0x101826710>, '__module__': '__main__', '__qualname__': 'TestMeta', 'cx': 0, '__init__': <function TestMeta.__init__ at 0x1018239d8>}
            cls.opened.__exit__(None, None, None) # cls_ is Meta_
            return type.__new__(cls, name, bases, dict(classdict))
     
    class TestMeta(metaclass=Meta_):            
        cx = tf.Variable(0, trainable=False, dtype=tf.int32, name="cx")
        def __init__(self):
            self.x = tf.Variable(0, trainable=False, dtype=tf.int32, name="x")
     
     
    def demo_meta():
        t= TestMeta()
        print(t.cx, t.x)
     
    if __name__ == '__main__':
        demo_meta()


    Enfin, une autre approche serait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    with tf.name_scope("scope"):
        from a import A
    Mais je n'ai pas envie d'appliquer le context à tout l'import (y compris aux import situés dans a.py). Voyez-vous un mécanisme d'import avancé qui permette de n'executer que A pendant l'import (ca me semble déraisonnable, mais bon ...) ?

  7. #7
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Voici un exemple pour récupérer deux arguments foo et bar dans __prepare__ et __new__ :
    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
    class Meta_(type):
     
            @classmethod
    	def __prepare__(metacls, name, bases, foo, bar):
    		print("__prepare__ : " + foo + bar)
    		return {}
     
    	def __new__(cls, name, bases, classdict, foo, bar):
    		print("__new__ : " + foo + bar)
    		return type.__new__(cls, name, bases, dict(classdict))
     
     
    def f() -> int:
    	print("appel de f")
    	return 42
     
     
    class TestMeta(metaclass=Meta_, foo = "foo", bar = "bar"):
    	x = f()
     
     
    if __name__ == '__main__':
    	t = TestMeta()
    Ce code affiche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    __prepare__ : foobar
    appel de f
    __new__ : foobar

  8. #8
    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
    Merci pour l'explication.

    Donc, tu passerais le context ouvert (foo par example) dans la signature de la classe ? Il me semblait préférable de le passer non encore ouvert. Il serait donc ouvert avant d'entrer dans la métaclasse. Comment assurer qu'il soit fermé en cas d'erreur ?

    De plus, dans mon cas, l'argument "TestMeta" doit être le nom de la classe. Je pensais donc passer uniquement le callback tensorflow.name_scope dans la signature, et l'appeler avec le nom de la classe dans __prepare__.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    """   Utilise le contexte ouvert dans la signature de TestMeta """
    class Meta_(type):
            @classmethod
    	def __prepare__(metacls, name, bases, opened):
    		return {}
     
    	def __new__(cls, name, bases, classdict, opened):
    		opened.__exit__(None, None, None)
    		return type.__new__(cls, name, bases, dict(classdict))
     
    class TestMeta(metaclass=Meta_, opened=tensorflow.name_scope("TestMeta").__enter__()):
    	x = f()

    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
     
    """   Utilise le contexte non-ouvert dans la signature de TestMeta
    Problème: ou stocker la valeur renvoyée par  context.__enter__() ?
    """
    class Meta_(type):
            @classmethod
    	def __prepare__(metacls, name, bases, context):
                    metacls.opened = context.__enter__()
    		return {}
     
    	def __new__(cls, name, bases, classdict, opened):
    		metacls.opened.__exit__(None, None, None)
    		return type.__new__(cls, name, bases, dict(classdict))
     
    class TestMeta(metaclass=Meta_, opened=tensorflow.name_scope("TestMeta")):
    	x = f()

  9. #9
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Après réflexion, on pourrait construire directement le contexte dans __prepare__ puis le fermer dans __new__.

    Je ne connais pas tensorflow, donc je vais utiliser open dans mon exemple :
    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
    class Meta_(type):
     
            @classmethod
    	def __prepare__(metacls, name, bases, cheminFichier):
    		fichier = open(cheminFichier, 'w')
    		try:
    			fichier.write('__prepare__\n')
    			return {'Meta_fichier' : fichier}
    		except:
    			fichier.close()
    			raise
     
    	def __new__(cls, name, bases, classdict, cheminFichier):
    		fichier = classdict['Meta_fichier']
    		try:
    			fichier.write('__new__\n')
    			return type.__new__(cls, name, bases, dict(classdict))
    		finally:
    			fichier.close()
     
     
    def f(fichier) -> int:
    	try:
    		fichier.write('appel de f\n')
    		return 42
    	except:
    		fichier.close()
    		raise
     
     
    class TestMeta(metaclass=Meta_, cheminFichier = 'test.txt'):
    	x = f(Meta_fichier)
     
     
    if __name__ == '__main__':
    	t = TestMeta()
    Dans le fichier "test.txt", cela écrit bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    __prepare__
    appel de f
    __new__
    Edit 18h34 : correction dans f.

  10. #10
    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
    Super ! On peut utiliser classdict pour récupérer ce qui est émis par __prepare__.

    Est-ce que cela donne les mêmes garanties que with en ce qui concerne la gestion des exceptions ? Peut-elle se produire entre les appels à __prepare__ et __new__ ?

  11. #11
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par shaiHulud Voir le message
    Est-ce que cela donne les mêmes garanties que with en ce qui concerne la gestion des exceptions ?
    Hélas, dans mon exemple, avant mon édition de 18h34, j'avais oublié de gérer le cas où f lançait une exception.

    Après une deuxième réflexion, il vaut probablement mieux utiliser les solutions données par wiztricks dans son premier message, sans utiliser de métaclasse.

    Si je les applique à open, cela donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def f(fichier) -> int:
    	fichier.write('appel de f\n')
    	return 42
     
    class MaClasse:
    	pass
     
    with open('test.txt', 'w') as fichier:
    	MaClasse.x = f(fichier)
     
    if __name__ == '__main__':
    	m = MaClasse()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def f(fichier) -> int:
    	fichier.write('appel de f\n')
    	return 42
     
    with open('test.txt', 'w') as fichier:
    	MaClasse = type('MaClasse', (), { 'x' : f(fichier) }) # Rq : "'x' :", pas "x =".
     
    if __name__ == '__main__':
    	m = MaClasse()
    Le code sera moins difficile à maintenir.

  12. #12
    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
    Effectivement, __new__ n'est pas appelée si f lance une exception.

    Wrapper le contexte dans un générateur fournit une solution partielle. En cas d'erreur, la collection du generateur par le GC fermera le contexte.

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    """ Some mocking """
    class struct: pass
    class _name_scope(object):
        def __init__(self, *a): self.a = a
        def __enter__(self):
            print("in _name_scope", self.a)
            return self
        def __exit__(self, *b):
            print("out _name_scope", self.a)
            return self
    def _Variable(*a, **k):
        print("Variable", a, k)
        # assert False
        return a[0]
     
    tf = struct()
    tf.name_scope = _name_scope
    tf.Variable = _Variable
    tf.int32 = None
     
    class Meta_(type):
        @staticmethod
        def gen():
            with tf.name_scope("TestMeta") as entered: yield entered             
        @classmethod
        def __prepare__(metacls, name, bases):
            cm_wrapper = metacls.gen() # Either GC or __new__ will close context
            opened = next(cm_wrapper)                    
            return {"cm_wrapper":cm_wrapper}
     
        def __new__(cls, name, bases, classdict):       
            cm_wrapper = classdict.pop("cm_wrapper")
            cm_wrapper.close()
            return type.__new__(cls, name, bases, dict(classdict))
     
    class TestMeta(metaclass=Meta_):            
        cx = tf.Variable(0, trainable=False, dtype=tf.int32, name="cx")
        def __init__(self):
            self.x = tf.Variable(0, trainable=False, dtype=tf.int32, name="x")
     
     
    def demo_meta():
        t= TestMeta()
        print(t.cx, t.x)
        print(TestMeta.__dict__)
     
    if __name__ == '__main__':
        demo_meta()

  13. #13
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Ouh là, attention avec le GC.

    Extrait de The Python Language Reference (c'est moi qui graisse) :
    « CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. See the documentation of the gc module for information on controlling the collection of cyclic garbage. Other implementations act differently and CPython may change. Do not depend on immediate finalization of objects when they become unreachable (so you should always close files explicitly). »

    En résumé, si tu te reposes sur le GC, alors tu n'auras pas de garantie sur quand la fonction __exit__ de ton générateur sera appelée. Ça se passera peut-être bien avec l'implémentation actuelle de CPython, mais ce ne sera probablement pas le cas sur d'autres implémentations comme PyPy et ça ne sera peut-être pas le cas non plus sur une future version de CPython.

  14. #14
    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
    Merci pour l'avertissement.

    Ici pas de cycles. Je me dis qu'il suffit de rajouter un contexte à l'extérieur de la classe, dont la méthode exit attends que le contexte interne aie bien été fermé. Ca créera peut etre une boucle infinie dans certaines implémentations de python, mais au moins elle sera visible à l'utilisateur (par example un timeout). De plus, dans l'usage que j'ai de tensorflow (et même de Python en général), il est assez rare de récupérer d'une exception se produisant au moment de la création d'une classe.

    Maintenant, si je dois ajouter un second contexte pour gérer ca de manière sale, autant mettre le contexte d'intérêt à l'extérieur comme le suggèrait Wiztricks.

    J'essayais d'éviter cette solution car pour mon problème, cela contraint un peu plus l'utilisateur: il faut que l'argument du contexte soit le nom de la classe, que le contexte ouvert soit assigné à la classe pour être réutilisé par les méthodes statiques... autant de détail que j'aurais voulu automatiser.


    Encore un grand merci à tous les 2 pour votre temps et vos réponses !

  15. #15
    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
    Petite précision: la solution avec metaclasse peut etre implémentée avec une factory de decorateur.
    - La factory ouvre le contexte avant de renvoyer le décorateur (ce que faisait __prepare__).
    - La decorateur ferme le contexte lorsqu'il recoit la classe (ce que faisait __new__).

    Ca ne résoud pas la gestion des exceptions: le décorateur n'est pas appelé (tout comme __new__ dans l'approche metaclasse) si la classe décorée soulève une erreur.

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

Discussions similaires

  1. Réponses: 35
    Dernier message: 10/11/2008, 20h14
  2. Réponses: 4
    Dernier message: 26/08/2005, 11h39
  3. Demande d'information pour ajout d'API Java dans eclipse
    Par BernardT dans le forum Eclipse Java
    Réponses: 6
    Dernier message: 07/07/2005, 17h08
  4. script pour ajouter des utilisateurs postgres
    Par xopos dans le forum PostgreSQL
    Réponses: 6
    Dernier message: 16/08/2004, 10h49

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