Je souhaite faire un decorateur qui me retourne ce qui est cree dans la fonction a laquelle je l'attache.
@registerChanges
def test():
a = SomeObject()
return True
b = test()
Par exemple, dans le cas present, b contiendra True et l'instance de a, creee dans la fonction. Mon decorateur enregistre les classes instancees (en vrai, il ne s'agit pas de classes, mais peu importe, le probleme ne porte pas la dessus), execute la fonction, et retourne le tout. Jusqu'ici, pas de probleme.
Sauf que je souhaiterai, en cas d'erreur, recuperer malgre tout les classes qui ont ete crees. Le souci c'est que si une exception est raise dans mon decorateur, il ne va pas jusqu'au return, la fonction test() n'ira pas non plus jusqu'a son return, et la variable b ne sera meme pas creee. Est-ce quelqu'un aurait une idee de comment proceder pour raise une erreur ET recuperer une valeur return malgre tout ?
J'ai un peu de mal a expliquer clairement mon probleme, donc si je peux vous aider, n'hesitez pas a me demander des details sur tel ou tel point ! D'avance, merci =]
(si ca peut aider, voici a quoi ressemble le decorateur)
def registerChanges(func):
def wrapper(*args, **kwargs):
functionReturn = None
createdNodes = []
try:
# adds a callback to store every new object in the list 'createdNodes'
functionReturn = func(*args, **kwargs)
except:
raise
return functionReturn, createdNodes
return wrapper
C'est assez specifique, donc je ne suis pas sur que ca aide de savoir le pourquoi du comment, mais dans le doute.... :
C'est pour utiliser dans un soft de 3d (autodesk maya), sur une fonction qui cree des objets 3d. Je souhaite 'enregistrer' tous les objets 3d crees, de sorte a pouvoir appeler une fonction 'undo' par la suite, qui supprimera tous les objets que j'ai cree.
Donc tout le probleme, c'est en cas d'erreur : je veux, en cas d'erreur, que l'erreur, quelle qu'elle soit, remonte jusqu'a l'utilisateur, mais je souhaite quand meme recuperer la liste contenant tous les elements qui ont ete crees pendant la fonction jusqu'a ce qu'elle atteigne l'erreur.
Sinon tu peux très bien faire un try / except qui écrit ton erreur dans un fichier text, et tu rajoutes dans le finally ton code que tu dois à tout prix executer .
bonne idee, mais comme tu dis, malheureusement je voudrai mon erreur dans le traceback. Ce serait trop lour d'avoir a ecrire / lire un fichier externe, il me faudrait une solution 'seamless'
Ce qui me pose probleme, c'est que des que python rencontre une erreur, le programme s'arrete. Des qu'il rencontre un return, il s'arrete egalement.
Je voudrai pouvoir raise mon erreur tout en retournant une valeur. La, si je raise d'abord et que je return ensuite, le script narrive jamais jusqu'au return, et si je return dabord et raise ensuite, je n'ai jamais d'erreur puisque le script narrive pas jusque la.
Sauf que pour récupérer le retour tu serais bien obligé de traiter l'erreur. Donc, pourquoi faire ça ? Que voudrais-tu qu'il se passe quand une erreur se produit ?
Je ne sais pas comment est architecturé ton code, mais tu pourrais faire en sorte d'écrire dans une liste accessible de l'extérieur, voire même de faire de cette liste un attribut de l'erreur si c'est vraiment nécessaire. Mais je continue de penser que tu conçois mal ton problème.
C'est tout a fait possible que je concoive mal mon probleme effectivement, et je me suis aussi pose la question. Mais si tel est le cas, alors je souhaiterai une explication sur comment traiter mon truc autrement
La technique d'ecrire dans une liste definie en dehors est cool, et il se trouve que j'ai essaye aussi, pensant que ce serait la soluce Sauf que non, puisque, toujours pareil, DES que l'erreur est raise, la fonction s'arrete, et donc ne pourrai transmettre aucune donnee au niveau d'au dessus (i.e. au module qui l'a appelee).
La seule methode que je vois, c'est de recuperer l'erreur sous forme d'objet, et, en dehors de la fonction, de la raise si elle existe, mais le probleme avec cette methode est que le stack trace est a la ramasse
A la limite, je serai ok pour avoir une structure differente, je ne veux pas forcer python a fonctionner d'une maniere qu'il n'est pas cense supporter. Tout mon code est la, entwanne, donc tu vois comment c'est organise. Si tu as une suggestion de comment faire ce que je souhaite faire en organisant mon code different, n'hesite pas, ce sera plus que bienvenue !
oui, comme je disais, l'idee du fichier est cool et je n'y avais pas pense. Malheureusement, pour un usage intensif (et il s'agira la d'un usage intensif !), ca n'est pas viable, j'en ai peur =[
Idealement, il faut que pour la personne qui utilise la fonction, l'operation soit completement transparente. Enfin plus precisement, la structure finale ressemble a ca :
class Abstract(object):
'''
cette classe n'est pas exposee a l'utilisateur
'''
@registerChanges
def a(self):
pass
class X(Abstract):
def a(self):
# l'utilisateur fait ce qu'il a a faire ici
L'utilisateur final ne doit donc meme pas avoir connaissance du systeme
La technique d'ecrire dans une liste definie en dehors est cool, et il se trouve que j'ai essaye aussi, pensant que ce serait la soluce 
Sauf que non, puisque, toujours pareil, DES que l'erreur est raise, la fonction s'arrete, et donc ne pourrai transmettre aucune donnee au niveau d'au dessus (i.e. au module qui l'a appelee).
Si la liste est extérieure, tu n'as pas besoin de la retourner.
fruity' a écrit:
Tout mon code est la, entwanne, donc tu vois comment c'est organise.
Pas vraiment non, je vois juste un vague extrait.
Tu n'explicites pas ce que tu veux faire en cas d'erreur : arrêter le programme, juste afficher un message, quelque chose d'autre ?
Sauf que je souhaiterai, en cas d'erreur, recuperer malgre tout les classes qui ont ete crees.
Pour donner plus de detail, je souhaite, en cas d'erreur, arreter le programme (i.e. raise l'erreur) ET recuperer la variable return par ma fonction (ou en l'occurrence, par mon decorateur, puisque la fonction a error, elle n'a pas pu atteindre son return)
Et j'insiste, tout mon code est la, je t'assure Je peux t'envoyer une capture ecran de mon editeur, si ca peut t'aider ? Mais je doute que ca contribue beaucoup a la resolution de mon probleme
La technique de la liste exterieure est peut-etre la solution effectivement. Ma liste etait definie dans mon decorateur (registerChanges), donc j'avais besoin de la return pour la faire 'sortir' de ma fonction. Mais je peux essayer de la creer en dehors de tout appel de fonction, et la faire passer dans la fonction pour qu'elle soit ecrite au fur et a mesure du process. J'essayerai ce soir. D'ici la, si d'autres solutions vous viennent, je suis toujours preneur, cette methode ne me semblant pas tres propre en terme d'organisation du code.
(encore une fois, si quelque chose n'est pas clair, n'hesitez pas a me demander des explications)
Je lis et relis tes posts, et tout comme entwanne, je ne comprends pas ce que tu veux faire. J'essaie de reprendre pas à pas ce que tu as indiqué. Tout d'abord ton petit exemple du premier post:
fruity' a écrit:
@registerChanges
def test():
a = SomeObject()
return True
b = test()
Par exemple, dans le cas present, b contiendra True et l'instance de a, creee dans la fonction.
Exemple bizarre, puisque b ne contiendra que ce que retourne la fonction. Et elle ne retourne que True. l'objet SomeObject ayant été créé en local sera détruit lorsque la fonction retournera. Si au moins tu avais un truc du style return True, a, je pourrais comprendre. Mais là, pas vraiment...
fruity' a écrit:
Donc tout le probleme, c'est en cas d'erreur : je veux, en cas d'erreur, que l'erreur, quelle qu'elle soit, remonte jusqu'a l'utilisateur, mais je souhaite quand meme recuperer la liste contenant tous les elements qui ont ete crees pendant la fonction jusqu'a ce qu'elle atteigne l'erreur.
Il faudrait comprendre comment les objets créés par la fonctions sont retournés. Avec les exemples que tu as donné, ils ne sont pas retournés. Donc la question est : dans ton cas concret où vont ces objets ?
Dan, justement, je souhaitais que b return ce que retourne la fonction ET une autre variable, geree par le decorateur. Comme tu dis, l'instance de SomeObject() est detruite une fois sortie de la fonction, je voulais donc la 'relayer' au niveau de mon decorateur, qui changeait ce que la fonction return (puisque le True retourne par ma fonction test() est bien 'relaye', apres tout, dans le decorateur lui-meme)
Quoiqu'il en soit, c'est bon, entwanne a rempli a merveille le role du canard en plastique, et j'ai pu regler mon probleme =]
La solution n'etait pas un decorateur, mais un 'wrapper' de fonction, plus simplement. J'ai donc une fonction qui prend en premier argument une autre fonction, et en second argument une liste, qui est updatee au fur et a mesure puisque passee en reference, de sorte qu'en cas d'erreur, je recupere ma liste up to date, ET mon erreur est raise malgre tout.
× 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.
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique