Ben fred1599, c'est tout simple : une fois que tu as défini ton décorateur, les deux codes suivants sont équivalents :
@deco
def f(x):
blabla
def f(x):
blabla
f = deco(f)
Candide, tu pensais vraiment que le boarf de xarch voulait avoir une valeur pédagogique ? À mon avis il est surtout là pour relativiser ce que dit fred1599 et dire que, finalement, les décorateurs, c'est conceptuellement très simple (ah, c'est sûr, il faut connaître les fonctions d'ordre supérieur. Mais encore une fois, avec un minimum de pratique en python ou - mieux - dans un langage fonctionnel, ça ne devrait poser aucun problème).
Ce que je disais était sur un scope plus large que Python en lui-même.
Si on se met à la place d'un débutant en programmation qui aurait commencé son apprentissage avec "un langage fonctionnel" (et ça existe… mes premiers cours d'info étaient en CamL), je ne serais pas étonné qu'il saisisse relativement facilement l'usage de features comme les map/reduce/closures/décorateurs, et se retrouve comme un con devant une boucle while, ou la gestion des exceptions.
Tu vois la pédagogie ne doit pas couvrir que 50 % des utilisateurs, mais 90 à 95 % si on considère que les 5 à 10 autres pourcents, se sont plutôt des gens qui y mettent de la mauvaise volonté.
On peut donc dire ( ton code ne me permettra pas de m'améliorer, ce n'est pas une base sur laquelle je peux m'appuyer ) que pédagogiquement parlant ce n'est pas un code suffisant.
D'ailleurs je ne suis pas sûr qu'un seul code permet d'avoir une base sur les décorateurs.
Le problème c'est que même dans les docs officielles c'est très mal expliqué concrètement, et je dirais que c'est un peu normal car c'est plus considéré comme du sucre syntaxique.
Mais comme tout sucre, c'est pratiquement toujours inutile ou non optimisé.
Tu veux bien arrêter de toujours parler de « pédagogie » ? On dirait Shivaan qui parle de « respect ». À force, ça perd son sens et son intérêt comme mot.
@josmiley : tout ce que montre le second code, c'est qu'une fonction n'est qu'un objet comme un autre.
Quand tu appelles une fonction en python, c'est, pour résumer grossièrement comme quand tu appelles la méthode __call__ d'un objet quelconque. Au final, le décorateur va remplacer "l'instance" de la fonction par une version améliorée d'elle-même, un peu comme quand tu fais maliste=sorted(maliste) sur un objet quelconque.
Je pense qu'il est difficile de fournir des explications plus simples comme ça sans schéma.
Comme tout sucre, parler d'optimisation n'a pas de sens... Une façon plus agréable d'écrire exactement la même chose n'a rien à voir avec une optimisation.
Je ne vois vraiment pas ce qui n'est pas clair dans ce que j'ai expliqué. Le deuxième code est tout ce qu'il y a de plus banal en Python, et le premier lui est exactement équivalent.
Je ne vois vraiment pas ce qui n'est pas clair dans ce que j'ai expliqué. Le deuxième code est tout ce qu'il y a de plus banal en Python, et le premier lui est exactement équivalent.
Euh... Oui je l'ai compris ton code, ce que je veux dire c'est que ton code est clair pour toi, moi mais pas pour josmiley qui pourtant est un utilisateur expérimenté.
les décorateurs c'est du sucre syntaxique, mais c'est aussi une fonction, pourquoi ne pourrait-elle pas être optimisée ou optimiser?
Ce que je veux dire, c'est surtout que le sucre syntaxique (même si des fois je le fais aussi) est pratiquement toujours inutile et au dépend d'une difficulté dans la lisibilité du code en plus.
Enfin bref, le 2ème code est beaucoup plus lisible que le 1er, en ce qui me concerne en tout cas.
Ben fred1599, c'est tout simple : une fois que tu as défini ton décorateur, les deux codes suivants sont équivalents
Je suis sûr que fred le sait. Ce n'est pas parce qu'on comprend tous les mots d'une histoire drôle qu'on va forcément rire. C'est pas parce qu'on connait la lettre E, le lettre m, la lettre c et qu'on sait ce qu'est un carré qu'on a compris la relativité.
Citation : Orrita
Candide, tu pensais vraiment que le boarf de xarch voulait avoir une valeur pédagogique ?
Une valeur condescendante
Citation : Orrita
À mon avis il est surtout là pour relativiser ce que dit fred1599 et dire que, finalement, les décorateurs, c'est conceptuellement très simple
Sauf que si tu réduis les décorateurs à leur pure définition, comme le dit Kent's Korner , tu t'en passes. Bien évidemment, ce qui fait que la notion de décorateur est complexe est la richesse de ses situations d'utilisation. Rien que le décorateur du toy-example résolu par Nohar contient la définition d'une fonction elle-même décorée. Tout ça à travers un exemple qui n'est pas vraiment convaincant comme tu le reconnais toi-même.
Citation : Orrita
Mais encore une fois, avec un minimum de pratique en python ou - mieux - dans un langage fonctionnel, ça ne devrait poser aucun problème).
OK et si ça en pose, tu proposes quoi ? le gaz ou la corde ?
je ne comprends pas parce que je ne vois pas à quoi ça peut servir ...
exemple: j'ai rien pigé à property() jusqu'au jour où j'ai eu besoin d'un système qui modifie dynamiquement des attributs; et là qq1 m'a dit: "regardes property()..." et c'est devenu clair.
donc, sans comprendre l'utilité des décorateurs, je ne risque pas d'en comprendre le fonctionnement.
Le sucre syntaxique n'a pas pour but d'être utile, mais de rendre la lecture plus agréable... Et avec un peu d'habitude, le premier code est effectivement plus agréable à lire.
josmiley, en soi les décorateurs n'apportent rien (tout comme property : on pourrait avoir le même résultat autrement). Mais c'est comme dire qu'une fonction n'apporte rien parce qu'on pourrait réécrire le code à chaque appel.
candide, je reconnais surtout que critiquer les décorateurs en se basant sur l'exemple choisi est débile. Personne de censé n'utiliserait cet exemple dans le cas réel, c'est évident. Il reste quand l'utilisation que j'en fais, à savoir s'en servir pour tester la validité de son code, est entièrement justifiée.
Si ça pose des problèmes, je recommande de se mettre un peu plus sérieusement à python.
Arrête d'insister, Orrita, candide est prof de fac. Des vrais cons, il en croise tous les jours beaucoup plus que toi, donc il a raison.
josmiley> Je croyais que tu utilisais @property ? Tu utilises un truc utile qui utilise les décorateurs. Techniquement, tu devrais en déduire que les décorateurs sont utiles eux aussi.
L'idée des décorateurs est de te permettre de rajouter un comportement à une fonction sans modifier ton code, en la "décorant". Tu peux t'en servir pour ajouter un système de cache comme ici, pour l'ajouter à un callback, pour automatiquement loguer ses entrées et ses sorties (voir l'exercice de NoHaR euh, ailleurs)… Tu sépares le code de cette fonction (qui est pur) avec l'effet rajouté (une décoration).
Mais il n'y a pas de secret, c'est en pratiquant que tu arriveras à sentir le truc ou pas. Par contre ça sert à rien de répéter 4 fois que tu vois pas à quoi ça sert.
donc, sans comprendre l'utilité des décorateurs, je ne risque pas d'en comprendre le fonctionnement.
Absolument.
Citation : Orrita
Le sucre syntaxique n'a pas pour but d'être utile, mais de rendre la lecture plus agréable... Et avec un peu d'habitude, le premier code est effectivement plus agréable à lire.
Donc, pour comprendre les décorateurs, il faut aller derrière le sucre syntaxique et comprendre certains contextes et un contexte, c'est du temps, de l'expérience, du questionnement, tout sauf le simplisme dont tu n'arrives pas à sortir, et dire qu'on est sur le siteduZÉRO, là pour le coup, coefficient empathique = ZÉRO.
donc, sans comprendre l'utilité des décorateurs, je ne risque pas d'en comprendre le fonctionnement.
Absolument.
Bullshit. On peut comprendre le principe (et, avec un peu plus d'effort, le fonctionnement) des décorateurs sans arriver à les appliquer. C'est pas difficile : un décorateur est une fonction qui prend une fonction en argument, et renvoie une autre fonction. C'est peut-être peu naturel pour des gens qui ont décidé de ne pas chercher à faire d'effort, mais ça n'est pas difficile pour autant.
DE PLUS : de manière évidente, josmiley code en Python comme on coderait en Java, il n'a aucune expérience avec ce langage, et il a certainement été (mal) influencé par une trop grande pratique d'autres langages plus idiots que Python.
Bon, alors je dois être un génie pour avoir compris que les décorateurs étaient simples. Désolé de vous ennuyer avec mon niveau hors de portée de débutants comme vous.
je crois que je viens de piger un truc en comparent aux class ...
pour un décorateur donné; les fonctions décorées doivent avoir un fonctionnement commun.
est-ce que je peux comparer un décorateur à une méthode commune à des class différentes ?
par exemple str.count() et list.count() ...
josmiley> Qu'est-ce que tu ne comprends pas dans "un décorateur est une fonction qui accepte une fonction en argument, et renvoie une autre fonction" ?
josmiley> Qu'est-ce que tu ne comprends pas dans "un décorateur est une fonction qui accepte une fonction en argument, et renvoie une autre fonction" ?
non mais je crois que j'ai compris; en prenant du recul ... pas tout mais au moins le principe.
Je tenais à faire remarquer que l'utilisation d'un try/except en lieu et place du test de présence (in) améliore un peu les performances :
$ python becnh.py
Fibo avec `in` : 3.22333653768
Fibo avec `try` : 2.57666349411
from functools import wraps
from time import time
def cached_in(fn):
fn.cachedict = {}
@wraps(fn)
def wrapper(*args):
argskey = tuple(args)
if argskey in fn.cachedict:
ret = fn.cachedict[argskey]
else:
ret = fn.cachedict[argskey] = fn(*args)
return ret
return wrapper
def cached_try(fn):
fn.cachedict = {}
@wraps(fn)
def wrapper(*args):
argskey = tuple(args)
try:
ret = fn.cachedict[argskey]
except KeyError:
ret = fn.cachedict[argskey] = fn(*args)
return ret
return wrapper
@cached_in
def fibo_in(n):
if n <= 1:
return 1
else:
return fibo_in(n-1) + fibo_in(n-2)
@cached_try
def fibo_try(n):
if n <= 1:
return 1
else:
return fibo_in(n-1) + fibo_in(n-2)
def bench(n, l):
t = time()
for i in xrange(n):
fibo_in(l)
t_in = time() - t
t = time()
for i in xrange(n):
fibo_try(l)
t_try = time() - t
return t_in, t_try
if __name__ == '__main__':
iter, n, l = 30, 30000, 50
res = [bench(n, l) for i in xrange(iter)]
print('Fibo avec `in` : ', sum(_[0] for _ in res)/float(iter)*100)
print('Fibo avec `try` : ', sum(_[1] for _ in res)/float(iter)*100)
Je pense que le plus difficile n'est pas de comprendre comment fonctionne un décorateur et à quoi ça sert, mais de savoir à quel moment et dans quelle situation on devrait les utiliser (en tout cas me concernant).
Je pense que le plus difficile n'est pas de comprendre comment fonctionne un décorateur et à quoi ça sert, mais de savoir à quel moment et dans quelle situation on devrait les utiliser (en tout cas me concernant).
ça te permet d'éviter des contrôles identiques dans toutes les fonctions de ton code.
Imaginons que tu es à tester le type d'un argument et que tu dois le faire dans 40 fonctions, tu ne vas pas taper ce code dans chaque fonction
if isinstance(arg, int):
#suite de ma fonction
à l'aide des décorateurs tu peux éviter de te retaper ces 2 lignes sur tes 40 fonctions, en ajoutant au-dessus de la fonction concernée le décorateur @testing_arg par exemple.
L'exemple de NoHaR (sur un autre sujet) était bien aussi : pour tracer les appels de fonctions, il est plus propre de mettre @trace devant plutôt que de rajouter au début et à la fin de chaque fonction le code en question...
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.