J'essaie de trouver une meilleure façon d'exécuter les fonctions suivantes. J'ai une série d'étapes à compléter, et en cas d'échec, je dois annuler l'étape précédente comme suit:
try: A = createA() except: return None try: B = createB(A) except: deleteA(A) return None try: C = createC(B) except: deleteB(B) deleteA(A) return None try: D = createD(C) except: deleteC(C) deleteB(B) deleteA(A) return None return D
Je préférerais ne pas me répéter si possible. Comment puis-je améliorer cela? Y a-t-il un modèle connu à suivre?
Une chose que j'ai envisagée serait d'ajouter deleteB (
) à deleteC ()
et deleteA ()
à deleteB ()
. Est-ce la meilleure façon de procéder?
4 Réponses :
Si vous regardez quelques modèles de conception, vérifiez ce qui suit:
C'est probablement ce que vous cherchez. En outre, les commandes peuvent avoir une action «annuler». Vérifiez également la question suivante, si elle contient un problème similaire que vous avez. meilleur modèle de conception pour la fonction d'annulation
Comme le soulignent les commentaires, c'est à cela que sert le protocole du gestionnaire de contexte. Cependant, si vous ne voulez pas encore approfondir ce qui est une fonctionnalité assez avancée, vous pouvez définir des fonctions anonymes lambda
au fur et à mesure, pour vous rappeler ce qu'il faut ranger ...
try: deleters = [] A = createA() deleters.append( lambda: deleteA(A) ) B = createB( A) deleters.append( lambda: deleteB(B) ) C = createC( B) deleters.append( lambda: deleteC(C) ) D = createD( C) return D except: for d in reversed( deleters): d() return None
Cela dépend de ce que signifie exactement «annuler». Par exemple. si A, B, C, D etc. sont des commandes utilisateur arbitraires et qu'il peut y en avoir un grand nombre dans n'importe quel ordre, alors vous devez probablement écrire une sorte d'abstraction autour de faire / annuler.
Si alternativement A, B, C, D etc. sont des ressources qui doivent être rangées (connexions à la base de données, fichiers, etc.), alors les gestionnaires de contexte peuvent être plus appropriés.
Ou peut-être A, B, CD sont une autre sorte de chose.
Un petit bout de code utilisant des gestionnaires de contexte:
class A: def __enter__(self): set things up return thing def __exit__(self, type, value, traceback): tear things down class B, C and D are similar def doSomethingThatNeedsToUseD(): try: with A() as a: with B() as b: with C() as c: with D() as d: d.doSomething() except: print("error")
Ce que vous recherchez s'appelle motif memento . C'est l'un des modèles de conception du GoF:
Sans violer l'encapsulation, capturez et extériorisez l'état interne d'un objet afin que l'objet puisse être restauré à cet état plus tard.
La seule façon de l'implémenter en utilisant python
pourrait être de trouver ici .
Un modèle à utiliser pourrait être le gestionnaire de contexte , que vous pouvez
__enter__
et__exit__
- vous avez peut-être utilisé ceci commeavec open ( ...) comme file_:
, par exemple, où il est utilisé pour fermer le fichier pour vous.Depuis Python 3.3, il existe
contextlib.ExitStack
en combinaison avec des gestionnaires de contexte pour de telles choses.Une façon de faire est d'écrire une fonction d'annulation qui englobe toutes vos fonctions
deleteX ()
et de l'appeler commeundo ([C, B, A])
, où il analyse vos objets pour les supprimer et appelledeleteX ()
en conséquence. Bien que ce ne soit probablement pas l'approche optimale.Je ne connais pas python, mais un équivalent à goto est en fait une bonne solution, même si cela fronce les sourcils. Voir ici pour une norme générale