【问题标题】:Best way to undo previous steps in a series of steps在一系列步骤中撤消先前步骤的最佳方法
【发布时间】:2019-06-25 03:44:46
【问题描述】:

我正在尝试找到一种更好的方法来执行以下功能。我有一系列步骤需要完成,如果有任何失败,我需要像这样撤消上一步:

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

如果可能的话,我不想重复自己。我该如何改进呢?是否有已知的模式可以遵循?

我考虑过的一件事是将deleteB() 添加到deleteC(),并将deleteA() 添加到deleteB()。这是最好的方法吗?

【问题讨论】:

  • 一种可以使用的模式可能是 上下文管理器,您可以使用 __enter____exit__ - 您可能已经像 with open(...) as file_: 一样使用过它,例如,在哪里它用于为您关闭文件。
  • 从 Python 3.3 开始,contextlib.ExitStack 与上下文管理器结合使用。
  • 一种方法是你可以编写一个撤销函数,它包含你所有的deleteX() 函数,并像undo([C, B, A]) 一样调用它,它解析你的对象以删除并相应地调用deleteX()。虽然这可能不是最佳方法。
  • 我不知道 python,但一些与 goto 等效的方法实际上是一个很好的解决方案,即使它不赞成。通用标准见here

标签: python optimization design-patterns coding-style


【解决方案1】:

如果您查看一些设计模式,请检查以下内容:

Command pattern

这可能就是您正在寻找的。此外,它的命令可以具有“撤消”操作。还要检查以下问题,如果它包含您遇到的类似问题。 best design pattern for undo feature

【讨论】:

    【解决方案2】:

    正如 cmets 所指出的,这就是上下文管理器协议的用途。但是,如果您还不想深入研究什么是相当高级的功能,那么您可以随时定义 lambda 匿名函数,以记住要整理的内容...

    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
    

    【讨论】:

      【解决方案3】:

      这取决于“撤消”的确切含义。例如。如果 A、B、C、D 等是任意用户命令,并且可能以任意顺序存在大量命令,那么您可能需要围绕 do/undo 编写某种抽象。

      如果 A、B、C、D 等是需要整理的资源(数据库连接、文件等),那么上下文管理器可能更合适。

      或者也许 A、B、C D 完全是其他类型的东西。

      使用上下文管理器的一小段代码:

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

      【讨论】:

        【解决方案4】:

        您正在寻找的东西称为纪念品模式。它是 GoF 设计模式之一:

        在不违反封装的情况下,捕获对象的内部状态并将其外化,以便稍后将对象恢复到该状态。

        使用python 实现它的一种方法是找到here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多