OVH Cloud OVH Cloud

new style class et descriptors pour meta programmation

13 réponses
Avatar
azamruk
Bonjour,

sur la page http://www.python.org/doc/2.2.1/whatsnew/sect-rellinks.html#SECTION000310000000000000000

L'auteur donne l'exemple suivant :

from eiffel import eiffelmethod

class C(object):
def f(self, arg1, arg2):
# The actual function
...
def pre_f(self):
# Check preconditions
...
def post_f(self):
# Check postconditions
...

f = eiffelmethod(f, pre_f, post_f)


en disant qu'il ne serait pas très compliqué d'écrire un module
permettant ce genre de choses.
Seulement voila, je n'arrive pas à imaginer comment faire.
Ce qui m'intéresse, c'est bien la méthode python pour écrire un tel
module et non le module lui même.

Si quelqu'un à une idéee, je suis preneur.
Merci et cordialement,

azam.

3 réponses

1 2
Avatar
Michel Claveau - abstraction méta-galactique non triviale en fuite perpétuelle.
Bonsoir !


Effectivement, cette cabane a l'air bien délabrée. C'est plutôt dommage.
Mais je ne pourrai pas aider, mon anglais ne dépassant pas le niveau de
Google-linguistique...


Michel Claveau
Avatar
azamruk
Amaury Forgeot d'Arc wrote in message news:<cnja4g$aik$...
Bonjour,



Bonjour,

J'ai une petite question sur les descripteurs.
En faisant des essais, je suis tombé sur un comportement que je ne
comprend pas.

Soit le code suivant :

class readonly(object) :
"""
Ne marche que pour un attribut de classe accédé par une instance
"""

def __init__(self, obj) :
self.__obj = obj

def __get__(self, obj, klass) :
return self.__obj

def __set__(self, obj, value) :
raise ReadOnlyError("forbidden")

class A(object) :
V = (1, 2, 3)
V = readonly(V)

# si V est accédé par une instance de A, ça marche pas mal
# si V est accédé par A, on ne passe pas par la méthode __set__
# et donc le descripteur est perdu à la première affectation

def __init__(self) :
self.__v = readonly(1000)
# ici readonly construit un objet banal,
# et __get__ n'est jamais appelée.


Du coup, ce readonly ne sert pas à grand choses...

Sinon, pour votre explication précédente sur les metaclass, si j'ai
bien comris, ça ne fonctionne que parce que le code de __init__ de la
metaclass est exécuté APRÈS la définition de la classe. Me trompés-je
?

Merci.

--
azam.

Avatar
Adrien Di Mascio
Bonjour,

Le Sun, 21 Nov 2004 04:47:11 -0800, azamruk a écrit :
En faisant des essais, je suis tombé sur un comportement que je ne
comprend pas.
Soit le code suivant :

class readonly(object) :
def __init__(self, obj) :
self.__obj = obj
def __get__(self, obj, klass) :
return self.__obj>
def __set__(self, obj, value) :
raise ReadOnlyError("forbidden")

class A(object) :
V = readonly((1, 2, 3))
# si V est accédé par une instance de A, ça marche pas mal
# si V est accédé par A, on ne passe pas par la méthode __set__
# et donc le descripteur est perdu à la première affectation

def __init__(self) :
self.__v = readonly(1000)
# ici readonly construit un objet banal,
# et __get__ n'est jamais appelée.



Effectivement, les descripteurs doivent être définis au niveau de la
classe pour que le mécanisme de lookup fonctionne correctement :

a.V sera transformé (si possible) en :
type(a).__dict__['V'].__get__(a, type(a))

A.V sera transformé (si possible) en :
A.__dict__['V'].__get__(None, V)

En ce qui concerne "__set__", elle n'est appelée que sur les instances,
et pas sur les classes, c'est pour ça, que contrairement au protoype de
__get__, elle ne prend pas un attribut "obj", et "objtype".

D'autre part, la précédence de lookup dépend du type de descritpeur
utilisé (DataDescriptor et NonDataDescriptor (des idées de traductions
potables ?)), à savoir qu'un DataDescriptor prend le pas sur une
variable d'instance, qui elle-même prend le pas sur un NonDataDescritpor

Exemple :
========
#####################################################################
## class DataDescriptor(object):
## def __init__(self, val, varname):
## self.val = val
## self.varname = varname
##
## def __get__(self, obj, objtype):
## print "__get__", self.varname
## return self.val
##
## def __set__(self, obj, val):
## print "__set__", self.varname
## self.val = val
##
## class NonDataDescriptor(object):
## def __init__(self, val, varname):
## self.val = val
## self.varname = varname
##
## def __get__(self, obj, objtype):
## print "__get__", self.varname
## return self.val
##
##
## class Test(object):
## x = DataDescriptor('valeur initiale de x', 'X')
## y = NonDataDescriptor('valeur initiale de y', 'Y')
##
## def __init__(self):
## self.x = 12 # (1)
## self.y = 13 # (2)
##
##
## # (1) : on surcharge Test.x, mais comme c'est un DataDescriptor,
## # self.x reste un descripteur, on passe par __get__ / __set__
## # (2) : on surcharge Test.y, mais c'est un un NonDataDescriptor,
## # on perd donc les appells __get__ / __set__
######################################################################

Sinon, pour votre explication précédente sur les metaclass, si j'ai
bien comris, ça ne fonctionne que parce que le code de __init__ de la
metaclass est exécuté APRÈS la définition de la classe. Me trompés-je
?
Le __init__ de la métaclasse est effectivement appelé à la fin de la

déclaration de la classe elle-même.

Cordialement,

Adrien.

1 2