2
votes

Meilleur moyen d'annuler les étapes précédentes en une série d'étapes

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 commentaires

Un modèle à utiliser pourrait être le gestionnaire de contexte , que vous pouvez __enter__ et __exit__ - vous avez peut-être utilisé ceci comme avec 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 comme undo ([C, B, A]) , où il analyse vos objets pour les supprimer et appelle deleteX () 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


4 Réponses :


0
votes

Si vous regardez quelques modèles de conception, vérifiez ce qui suit:

Modèle de commande

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


0 commentaires

0
votes

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


0 commentaires

0
votes

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")


0 commentaires

0
votes

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 .


0 commentaires