OVH Cloud OVH Cloud

Métaclasses

7 réponses
Avatar
evaisse
bonjour, en suivant l'exemple des m=E9taclasses avec python sur
wikipedia : http://fr.wikipedia.org/wiki/M%C3%A9taclasse

J'obtiens l'erreur suivante :
>pythonw -u "test_metaclasse.py"
Traceback (most recent call last):
File "test_metaclasse.py", line 28, in <module>
class A(object):
File "test_metaclasse.py", line 21, in __new__
if type(slot) is type(_trace):
NameError: global name '_trace' is not defined
>Exit code: 1

Et l=E0, comme je d=E9bute, ben j'ai un peu de mal =E0 comprendre... J'ai
beau ajouter "global _trace", rien n'y fait...

7 réponses

Avatar
NicolasP

Et là, comme je débute, ben j'ai un peu de mal à comprendre... J'ai
beau ajouter "global _trace", rien n'y fait...

Avec quelle version de Python et sur quel système ?


Nicolas

Avatar
Bruno Desthuilliers
evaisse wrote:
bonjour, en suivant l'exemple des métaclasses avec python sur
wikipedia : http://fr.wikipedia.org/wiki/M%C3%A9taclasse

J'obtiens l'erreur suivante :
pythonw -u "test_metaclasse.py"
Traceback (most recent call last):

File "test_metaclasse.py", line 28, in <module>
class A(object):
File "test_metaclasse.py", line 21, in __new__
if type(slot) is type(_trace):
NameError: global name '_trace' is not defined
Exit code: 1



Il y a effectivement une erreur dans le code de l'exemple. Plusieurs, en
fait. Voici une version corrigée (fonctionne ici avec python 2.4.x)

import types

class Tracer(type):
def __new__(metacls, name, bases, dct):
# définition d'une fonction wrapper pour les méthodes
def _wrapper(name, method):
# création d'une fonction permettant tracer une méthode
def _trace(self, *args, **kwargs):
print "(call %s)" % name
return method(self, *args, **kwargs)
# idiome: faire passer une fonction pour une autre
_trace.__name__ = method.__name__
_trace.__doc__ = method.__doc__
#_trace.__dict__._update(_method.__dict__)
_trace.__dict__.update(method.__dict__)
return _trace

# remplacement de toutes les méthodes par leur équivalent tracé
newDct = {}
for name, slot in dct.iteritems():
#if type(slot) is type(_trace):
if type(slot) is types.FunctionType:
#newDct[name] = _wrapper(slot)
newDct[name] = _wrapper(name, slot)
else:
newDct[name] = slot
# appel au constructeur de la super classe (type)
return type.__new__(metacls, name, bases, newDct)

Et là, comme je débute, ben j'ai un peu de mal à comprendre...


A moins que tu ne sois déjà un développeur expérimenté, les métaclasses
ne sont peut-être pas le meilleur point de départ...

J'ai
beau ajouter "global _trace", rien n'y fait...


Qu'est-ce que ça devrait changer à ton avis ?

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"


Avatar
Jean-Marc Pouchoulon
Bonjour,
Une question :
Comment a.get() déclenche l'appel à _trace.
Je comprend que __new__ et __init__ soient appelés lors de la
contruction de la classe , mais lors de l'accès à a.get que se passe t -il ?
(appel de getattribute mais ensuite ? )


jmp

evaisse wrote:
bonjour, en suivant l'exemple des métaclasses avec python sur
wikipedia : http://fr.wikipedia.org/wiki/M%C3%A9taclasse

J'obtiens l'erreur suivante :
pythonw -u "test_metaclasse.py"
Traceback (most recent call last):

File "test_metaclasse.py", line 28, in <module>
class A(object):
File "test_metaclasse.py", line 21, in __new__
if type(slot) is type(_trace):
NameError: global name '_trace' is not defined
Exit code: 1



Il y a effectivement une erreur dans le code de l'exemple. Plusieurs, en
fait. Voici une version corrigée (fonctionne ici avec python 2.4.x)

import types

class Tracer(type):
def __new__(metacls, name, bases, dct):
# définition d'une fonction wrapper pour les méthodes
def _wrapper(name, method):
# création d'une fonction permettant tracer une méthode
def _trace(self, *args, **kwargs):
print "(call %s)" % name
return method(self, *args, **kwargs)
# idiome: faire passer une fonction pour une autre
_trace.__name__ = method.__name__
_trace.__doc__ = method.__doc__
#_trace.__dict__._update(_method.__dict__)
_trace.__dict__.update(method.__dict__)
return _trace

# remplacement de toutes les méthodes par leur équivalent tracé
newDct = {}
for name, slot in dct.iteritems():
#if type(slot) is type(_trace):
if type(slot) is types.FunctionType:
#newDct[name] = _wrapper(slot)
newDct[name] = _wrapper(name, slot)
else:
newDct[name] = slot
# appel au constructeur de la super classe (type)
return type.__new__(metacls, name, bases, newDct)

Et là, comme je débute, ben j'ai un peu de mal à comprendre...


A moins que tu ne sois déjà un développeur expérimenté, les métaclasses
ne sont peut-être pas le meilleur point de départ...

J'ai
beau ajouter "global _trace", rien n'y fait...


Qu'est-ce que ça devrait changer à ton avis ?





Avatar
evaisse
Splendid !!
merci, avec ça je devrais pouvoir m'en sortir. J'utilise python2.5 et
ça fonctionne.
Plus qu'à comprendre comment maintenant...



Bonjour,
Une question :
Comment a.get() déclenche l'appel à _trace.
Je comprend que __new__ et __init__ soient appelés lors de la
contruction de la classe , mais lors de l'accès à a.get que se passe t -il ?
(appel de getattribute mais ensuite ? )


jmp

evaisse wrote:
bonjour, en suivant l'exemple des métaclasses avec python sur
wikipedia : http://fr.wikipedia.org/wiki/M%C3%A9taclasse

J'obtiens l'erreur suivante :
pythonw -u "test_metaclasse.py"
Traceback (most recent call last):

File "test_metaclasse.py", line 28, in <module>
class A(object):
File "test_metaclasse.py", line 21, in __new__
if type(slot) is type(_trace):
NameError: global name '_trace' is not defined
Exit code: 1



Il y a effectivement une erreur dans le code de l'exemple. Plusieurs, en
fait. Voici une version corrigée (fonctionne ici avec python 2.4.x)

import types

class Tracer(type):
def __new__(metacls, name, bases, dct):
# définition d'une fonction wrapper pour les méthodes
def _wrapper(name, method):
# création d'une fonction permettant tracer une méthode
def _trace(self, *args, **kwargs):
print "(call %s)" % name
return method(self, *args, **kwargs)
# idiome: faire passer une fonction pour une autre
_trace.__name__ = method.__name__
_trace.__doc__ = method.__doc__
#_trace.__dict__._update(_method.__dict__)
_trace.__dict__.update(method.__dict__)
return _trace

# remplacement de toutes les méthodes par leur équivalent t racé
newDct = {}
for name, slot in dct.iteritems():
#if type(slot) is type(_trace):
if type(slot) is types.FunctionType:
#newDct[name] = _wrapper(slot)
newDct[name] = _wrapper(name, slot)
else:
newDct[name] = slot
# appel au constructeur de la super classe (type)
return type.__new__(metacls, name, bases, newDct)

Et là, comme je débute, ben j'ai un peu de mal à comprendre...


A moins que tu ne sois déjà un développeur expérimenté, les m étaclasses
ne sont peut-être pas le meilleur point de départ...

J'ai
beau ajouter "global _trace", rien n'y fait...


Qu'est-ce que ça devrait changer à ton avis ?







Avatar
jean-marc pouchoulon
Splendid !!
merci, avec ça je devrais pouvoir m'en sortir. J'utilise python2.5 et
ça fonctionne.
Plus qu'à comprendre comment maintenant...


En fait il y a récriture des fonctions de A lors de la création de
l'instance a en _trace :

print inspect.getsource(a.__init__)
def _trace(self,*args, **kwargs):



print "(call %s)" % name
return method(self, *args, **kwargs)

print inspect.getsource(a.get)
def _trace(self,*args, **kwargs):



print "(call %s)" % name
return method(self, *args, **kwargs)

magique...



Avatar
Bruno Desthuilliers
Bonjour,
Une question :
Comment a.get() déclenche l'appel à _trace.


C'est le principe des décorateurs. La fonction d'origine est remplacée
par une autre fonction - en l'occurrence une fermeture (une fonction qui
trimballe avec elle l'environnement dans le quel elle a été définie).

Je comprend que __new__ et __init__ soient appelés lors de la
contruction de la classe , mais lors de l'accès à a.get que se passe t
-il ?
(appel de getattribute mais ensuite ? )


Il ne se passe rien de spécial à ce moment - c'est lors de la création
de l'objet class A que les fonctions définies dans le block class (et
donc passée en dernier argument au constructeur de la metaclasse sous la
forme d'un dictionnaire, avec les autres attributs définis au niveau de
la classe) sont remplacées par la fermeture (fonction _trace) retournée
par la fonction _wrapper.

En l'occurrence, on obtiendrait un résultat identique avec un simple
décorateur - à condition bien sûr de l'appliquer à toutes les fonctions
concernées.

Avatar
jean-marc pouchoulon


En l'occurrence, on obtiendrait un résultat identique avec un simple
décorateur - à condition bien sûr de l'appliquer à toutes les fonctions
concernées.


Ok et merci