【问题标题】:In python, how do I re-run a function if it throws an error在python中,如果抛出错误,我如何重新运行函数
【发布时间】:2020-06-15 13:57:36
【问题描述】:

下面是我的代码的 sn-ps,我想知道的是假设函数 main2() 是否由于某种原因抛出错误,我如何让我的异常再次运行相同的函数说 3 次才中断?

在这里补充一下,任何函数都可能引发错误(不仅仅是 main2()),而且我可能不仅有 3 个函数,而且还有更多函数

import numpy as np

def main():
    np.load('File.csv')

def main1():
    np.load('File1.csv')

def main2():
    np.load('File2.csv')

for i in range(1, 10):
    try:
        main()
        main2()
        main3()
    except Exception as e:
        print e
    else:
        break

【问题讨论】:

    标签: python error-handling try-except


    【解决方案1】:

    你可以用python retry decorator做到这一点

    @retry((Exception), tries=3, delay=0, backoff=0)
    def main2():
       np.load('File2.csv')
    

    这和你写的一样:

    error_counter = 0
        def main2():
           try:
              np.load('File2.csv')
           except:
              if error_counter < 3
                 error_counter += 1
                 main2()
              raise Exception("Will not try again, have tried 3 times")  
           error_counter = 0
    

    如果你想让它健壮和干净,你应该选择第一个解决方案。您可以在大型企业项目中重用的第一个解决方案,由于回退时间,它可以考虑磁盘负载、用户负载网络问题以及回退/延迟时间。

    如果您不使用时间延迟,您将在一秒钟内完成所有 3 次尝试。这对于某些例外情况很好,但是当遇到网络问题或磁盘问题时,您需要更复杂的解决方案。

    另外,请考虑不要捕获所有异常,缓存所有异常是一种不好的做法。 More info, why it is bad

    【讨论】:

    • 谢谢我刚刚修改了我原来的问题。它不仅仅是可能抛出错误的 main2() 它是一个假设的例子。 3 个函数中的任何一个都可能引发错误,而且很可能我将有 6-7 个函数。所以我需要灵活地重新运行任何抛出错误的函数
    • 您可以在每个需要它的函数上方使用装饰器,并指定要缓存的异常。我只包含 main2 作为基于原始问题的示例。
    • 这似乎对我有用,我将不得不对其进行更多测试,但到目前为止看起来不错。谢谢阿甘。
    【解决方案2】:

    这是一个你可以试试的成语:

    for _ in range(3):  # try 3 times
        try:
            main2()
            break       # as soon as it works, break out of the loop
        except Exception as e:
            print e
            continue    # otherwise, try again
    else:               # if the loop exited normally, e.g. if all 3 attempts failed
        pass
        # do_something...
    

    注意缩进。这里的else 附加到for,而不是try

    【讨论】:

    • 谢谢,我认为我需要的是三个函数中的任何一个都可能引发错误的灵活性(不仅仅是 main2())。老实说,随着时间的推移,我可能会拥有更多的功能,那么这将如何工作?
    • 每个人都有不同的try/except 夹具?取决于您的三个功能做什么,以及它们如何相互连接。你可以做的一件事是把它变成一个函数,你可以在其中传递n 尝试的次数和main2 要运行的函数,然后在你想要运行的任何函数上调用该函数。这将使您更简洁地运行它。
    【解决方案3】:

    不幸的是,实现自定义 retry 装饰器通常会有点痛苦。如果你想调整它们的逻辑或调整它们,它实际上会很快变得相当复杂。那里有一个名为 Backoff-Utils 的 Python 库,它支持非常健壮且易于扩展的重试/退避策略(完全披露:我有偏见,因为我是该库的作者)。

    在您的假设问题中,您可以在基于装饰器的策略中使用该库:

    from backoff_utils import backoff, apply_backoff, strategies
    
    @apply_backoff(strategies.Fixed, max_tries = 3, catch_exceptions = [type(ValueError)])
    def main2():
        # np.load('File2.csv')
        raise ValueError
        print("In main2")
    

    或者你可以在调用main2()时在基于函数的策略中使用它:

    result = backoff(main2,
                     max_tries = 3,
                     catch_exceptions = [type(ValueError)],
                     strategy = strategies.Fixed)
    

    当然,上面的代码 sn-p 是专门为完全按照您上面描述的而设计的。它使用线性策略(仅重试 3 次,尝试之间的默认延迟为 1 秒)。

    使用该库,您可以采用任意数量的其他重试/延迟策略,包括指数退避、斐波那契、线性渐进和多项式。您还可以自定义和创建自己的延迟策略。您可以合并自定义成功/失败处理程序,以及针对不同类型情况的不同替代路径。

    当然,所有这些灵活性对于您的特定用例来说都是多余的——您不需要那么多。但它可能比担心复制/粘贴/维护自己的重试装饰器更容易,并且如果您发现以后需要更复杂的重试策略,它会为您提供额外的内置选项。

    如果有帮助,您可以在这里找到一些非常详细的文档:https://backoff-utils.readthedocs.io/en/latest/index.html

    希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      你可以试试

      for i in range(1, 10):
          error_max = 3
          error_counter = 0
          try:
              main()
              try:
                  main2()
              except Exception as e:
                  counter += 1
                  if counter == 3:
                      raise e
                  else:
                      continue
              main3()
          except Exception as e:
              print e
          else:
              break
      

      此代码将运行函数main2(),直到出现 3 个错误,而在前 2 个错误时,它将再次运行循环。

      【讨论】:

        【解决方案5】:

        您应该处理特定函数中的所有错误,否则如果将所有函数的错误一起处理,则在其他函数之前的函数将抛出错误,并且控件将执行 except 块跳过它下面的其余代码尝试阻止。 自己试试吧:

        def main():
            # np.load('File.csv')
            raise ValueError
            print("In main")
        
        def main1():
            # np.load('File1.csv')
            raise ValueError
            print("In main1")
        
        def main2():
            # np.load('File2.csv')
            raise ValueError
            print("In main2")
        
        for i in range(1, 10):
            try:
                main()
                main2()
                main3()
            except Exception as e:
                print(e)
            else:
                break
        

        尝试以不同的顺序评论函数中引发的错误。 当在每个函数中处理错误时,每个函数都会被执行,而不会跳过循环中的剩余函数

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-18
          • 1970-01-01
          • 2014-01-13
          • 1970-01-01
          • 1970-01-01
          • 2018-09-15
          • 1970-01-01
          • 2023-01-25
          相关资源
          最近更新 更多