Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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.

10 réponses

1 2
Avatar
Yermat
azamruk wrote:
Bonjour,

sur la page http://www.python.org/doc/2.2.1/whatsnew/sect-rellinks.html#SECTION000310000000000000000
[...]
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.


Je comprends pas ta question...

As-tu regarder les sources python suivantes ?
/usr/lib/python2.3/Demo/metaclasses
/usr/lib/python2.3/Demo/newmetaclasses

http://www.python.org/doc/essays/metaclasses/Eiffel.py

--
Yermat

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

Moi non plus, je ne comprend pas la question. Peut-être devrais-tu expliquer
un peu le fonctionnement que tu attends : la programmation par contrat, ce
que devraient faire preconditions et postconditions ; etc.

@-salutations
--
Michel Claveau
Avatar
azamruk
"Michel Claveau - abstraction méta-galactique non triviale en fuite perpétuelle." wrote in message news:<419ba7aa$0$23504$...
Bonsoir !


Bonjour,


Moi non plus, je ne comprend pas la question. Peut-être devrais-tu expliquer
un peu le fonctionnement que tu attends : la programmation par contrat, ce
que devraient faire preconditions et postconditions ; etc.



Non, la programmation par contrat, je connais, ce n'est pas ce qui
m'intéresse ici.

Ce que je cherche, c'est comprendre les descriptors et les metaclass
en python.

L'auteur de l'article que j'ai cité donne un exemple d'utilisation, et
il explique que ce serait très facile à écrire.

Et justement, je ne trouve pas ça si facile.

Surtout, du code comme ça :

f = eiffelmethod(f, pre_f, post_f)

cette fonction (eiffelmethod), modifie le code de f pour qu'à chaque
appel les méthodes pre_f et post_f soient appelées.

C'est le même principel que staticmethod() en fait.

@-salutations


De même,
azam.

Avatar
azamruk
Yermat wrote in message news:<cnfmd6$3in$...

Je comprends pas ta question...



Je cherche juste à mieux comprendre les descriptors et les metaclass
des new class style.

L'exemple donné (contrats eiffel) est juste un exemple.

Un autre exemple : Ajouter une méthode de comptage d'accès à une
ressource ou à des méthodes (dans une bdd).


As-tu regarder les sources python suivantes ?
/usr/lib/python2.3/Demo/metaclasses
/usr/lib/python2.3/Demo/newmetaclasses



Je n'ai pas ces sources. Je suis sous Windows avec Python 2.3

http://www.python.org/doc/essays/metaclasses/Eiffel.py


Je regardes...

Avatar
Amaury Forgeot d'Arc
Bonjour,

azamruk wrote:
Ce que je cherche, c'est comprendre les descriptors et les metaclass
en python.


azamruk wrote:
cette fonction (eiffelmethod), modifie le code de f pour qu'à chaque
appel les méthodes pre_f et post_f soient appelées.


(Note: c'est en écrivant cette réponse que j'ai vraiment compris ce qui
suit. Désolé d'être un peu long, mais je suis tellement content d'avoir
compris, et comme je n'ai pas vu beaucoup de doc sur le sujet...)

D'abord les métaclasses, c'est plus simple.

1. Les Métaclasses
=================
Il faut se rappeler qu'une classe est elle-même un objet, et que
cet objet a donc une classe...
La métaclasse est la classe de la classe. Dans le cas général,
c'est "type" qui est la métaclasse de tous les objets. [1]
("type" a pour type "type". Si,si !)
La méthode __init__ de la métaclasse sert à construire la classe.

[1] en fait, il y a une 2ème métaclasse pour les objets "ancien régime":
<type 'classobj'>

Quand python évalue une instruction "class XXX(object): ...", il crée
un objet de classe 'type' (PyTypeObject *), et met dans son
dictionnaire (__dict__) les fonctions et variables que l'on
y a définies.
D'ailleurs l'instruction suivante fonctionne, et fait la même chose:
XXX = type("XXX", (object,), dict)




Et les métaclasses? Eh bien, on peut, en créant la classe, faire un peu
plus de travail. En d'autres termes, on peut vouloir dériver la classe
"type", mettre un peu de code dans la méthode __init__, et utiliser le
résultat pour créer nos propres classes.

Une fois la métaclasse définie, on pourrait écrire:
XXX = ma_metaclasse("XXX", (object,), dict)
ce qui est équivalent à la forme plus classique:



class XXX(object):
... __metaclass__ = ma_metaclasse



... <la suite...>

Pour des exemples (en anglais):
http://www.python.org/2.2.3/descrintro.html#metaclasses_examples

2. Les descripteurs
==================
C'est génial. C'est magique. Je viens de comprendre...
Toute la doc est là:
http://www.python.org/dev/doc/devel/ref/descriptor-invocation.html

Prenons l'exemple d'une classe "vide":
class A: pass
a = A()
Quand on met un objet dans son dictionnaire, on peut le retrouver de



différentes façons:
A.__dict__['t'] = 1.5
print A.__dict__['t']
1.5



print A.t
1.5



print a.t
1.5



Tout ça c'est pareil. On a l'impression que python va tout simplement
chercher l'attribut 't' d'abord dans le dictionnaire de l'objet indiqué,
puis dans le dictionnaire de sa classe, puis dans celui des classes de
bases. C'est ce que je croyais jusqu'ici.

...Sauf si l'objet est d'un type qui a défini des propriétés spéciales.
(__get__, __set__ ou __del__)

Dans ce cas, les deux dernières écritures: A.t et a.t peuvent renvoyer
des choses différentes !
Par exemple:
def f(): pass
print f
<function f at 0xa0c35a4>



A.__dict__['f'] = f
print A.__dict__['f']
<function f at 0xa0c35a4>



print A.f
<unbound method A.f>



print a.f
<bound method A.f of <__main__.A instance at 0xa0c682c>>




Donc, (et c'est ma définition):
un descripteur est un objet qui, mis dans une classe sous un certain
nom, est capable de surcharger l'accès à l'attribut qui porte ce nom.
On peut surcharger:
1- l'accès en lecture à l'attribut depuis la classe elle-même
2- l'accès en lecture à l'attribut depuis une instance de la classe
3- l'accès en écriture à l'attribut depuis une instance de la classe
4- la suppression de l'attribut depuis une instance de la classe

Voici quelques descripteurs dans python:
- une fonction classique (def xxx():...) est un descripteur: elle
renvoie une <unbound method> dans le case (1) et une <bound method> dans
le cas (2).
- staticmethod(f) retourne un descripteur qui renvoie la fonction f dans
les cas (1) et (2) (et qui ne prendra donc pas 'self' en argument). Cela
revient à "défaire" la règle ci-dessus.
- property(get,set,del) retoune un descripteur qui se renvoie lui-même
dans le cas (1), et qui appelle les fonctions 'get', 'set' et 'del' dans
les 3 autres cas.


3. eiffelmethod
==============
azamruk wrote:
cette fonction (eiffelmethod), modifie le code de f pour qu'à chaque
appel les méthodes pre_f et post_f soient appelées.
Pas tout à fait. eiffelmethod *renvoie* une fonction qui enchaîne les 3

appels: pre_f, f et post_f.


Voici la méthode (qui mène à la solution)
- il faut créer une classe eiffelmethod qui dérive de object.
- le constructeur de cette classe prend 3 arguments, la fonction,
la fonction "pre" et la fonction "post". Il suffit de recopier ces 3
objets dans des attributs de notre eiffelmethod.
- la classe eiffelmethod définit la méthode '__get__', qui doit
retourner une fonction.
- Seules les surcharges de type (1) et (2) sont utiles.
Pour le type (1), il faut renvoyer une fonction qui ne prend pas l'objet
en argument (comme dans l'appel: c.f(arg1,arg2) )
Pour le type (2), il faut renvoyer une fonction qui prend l'objet en
argument (comme dans l'appel: C.f(c,arg1,arg2) )
Remarque: le code des 2 fonctions est le même. Seulement dans le premier
cas, 'obj' est lié lors de la définition de la fonction. Dans le
deuxième, 'obj2' est une variable libre.

class eiffelmethod(object):
def __init__(self,func,pre,post):
self.func=func
self.pre =pre
self.post=post

def __get__(self, obj, typ):
if obj is not None:
def bound_method(*args,**kwargs):
if self.pre: self.pre (obj)
self.func(obj,*args,**kwargs)
if self.post: self.post(obj)
return bound_method
else:
def unbound_method(obj2,*args,**kwargs):
if self.pre: self.pre (obj2)
self.func(obj2,*args,**kwargs)
if self.post: self.post(obj2)
return unbound_method

Bravo pour avoir tout lu jusqu'ici !
Si ce n'est pas clair par endroits, dites-le moi. Je suis en train de
préparer une présentation de python pour mes collègues...

--
Amaury Forgeot d'Arc



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

Merci beaucoup pour cet article,que je lirai demain, avec attention, lorsque
je serai mieux réveillé...
Avoir un texte en français va m'être très utile, pour combler le même besoin
(qu'Azamruk) : comprendre un peu mieux métaclasses et decorators.

Bonne nuit
--
Michel Claveau
Avatar
Adrien Di Mascio
Bonjour,

Yermat wrote
Je comprends pas ta question...

J'avoue que je cerne mal aussi la question



Je cherche juste à mieux comprendre les descriptors et les metaclass
des new class style.
Dans ce cas, voici quelques de liens que tu as probablement déjà lus,

mais au cas où :

- http://users.rcn.com/python/download/Descriptor.htm (à lire vraiment)
- http://www.cafepy.com/articles/python_types_and_objects/python_types_and_objects.html

Cela dit, d'après ce que j'ai pu lire (en diagonale, désolé, le post
était un peu long pour moi ;-) du mail d'Amaury, il a l'air d'avoir bien
introduit la chose ...

Si tu as des questions précises sur ce que tu ne comprends pas
dans l'exemple Eiffel, n'hésite pas.

En espérant que ça aide,

Adrien.


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



[...]


Bravo pour avoir tout lu jusqu'ici !
Si ce n'est pas clair par endroits, dites-le moi. Je suis en train de
préparer une présentation de python pour mes collègues...



Merci beaucoup.
Ton explication est claire.

Je vais voir les liens que tu as indiqué.

Et bonne chance pour ta présentation.
azam.

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

Merci pour les liens, malheureusement peu utilisables, car n'étant pas en
français. Je ne rabat sur le mail d'Amaury...

@-salutations
--
Michel Claveau
Avatar
Amaury Forgeot d'Arc
Michel Claveau - abstraction méta-galactique non triviale en fuite
perpétuelle. wrote:
Merci pour les liens


Merci aussi. J'aurais gagné pas mal de temps si j'avais su...


malheureusement peu utilisables, car n'étant pas en français.


A propos, où en est le projet de traduction des docs python en
français ?
http://frpython.sourceforge.net/ n'a pas bougé depuis 2 ans...
Je suis prêt à aider, mais là, il y a vraiment un fossé à combler
(depuis la version 2.0.1 !)
Il y a-t-il un projet plus (r|d)écent autre part ?

--
Amaury Forgeot d'Arc

1 2