【问题标题】:Python - Conditionally Catching ExceptionsPython - 有条件地捕获异常
【发布时间】:2011-11-16 03:41:48
【问题描述】:

是否可以在 python 中有条件地捕获异常?我希望能够编写一个函数,以便调用者可以决定谁处理异常。

基本上,我想要这样的东西:

def my_func(my_arg, handle_exceptions):
    try:
        do_something(my_arg)
    except Exception as e if handle_exceptions:
        print "my_func is handling the exception"

我知道我可以编写一些杂乱无章的代码来做我想做的事,但如果有的话,我想要一个 Python 式的答案。
谢谢。

【问题讨论】:

    标签: python exception


    【解决方案1】:

    如果不想处理,可以重新引发异常:

    def my_func(my_arg, handle_exceptions):
        try:
            do_something(my_arg)
        except Exception, e:
            if not handle_exceptions:
                # preserve prior stack trace
                raise
    
                # Or, if you dont care about the stack prior to this point
                #raise Exception(e)
    
                # similarly, you can just re-raise e.  The stack trace will start here though.
                #raise e
            else:
                print "my_func is handling the exception"
    

    另一种选择是创建您自己的子类Exception 的异常(或特定异常,如urllib2.HTTPError),然后只捕获/抛出(raise)您的自定义异常:

    class MyException(Exception):
        def __init__(self, message):
            self.message = message
    
    class MyExceptionTwo(Exception):
        def __init__(self, message):
            self.message = message
        def __repr__(self):
            return "Hi, I'm MyExceptionTwo.  My error message is: %s" % self.message
    
    def something():
        if not tuesday:
            raise MyException("Error: it's not Tuesday.")
        else:
            raise MyExceptionTwo("Error: it's Tuesday.")
    
    def my_func(my_arg):
        try:
            something()
        except MyException, e:
            print e.message
        # Will pass MyExceptionTwo up the call chain
    
    def my_other_func():
        try:
            my_func(your_arg)
        except MyExceptionTwo, e:
            print str(e)
        # No need to catch MyException here since we know my_func() handles it
        # but we can hadle MyExceptionTwo here
    

    【讨论】:

    • 我想这行得通,但如果它永远不会被捕获,那会弄乱堆栈跟踪,对吧?
    • @speedplane 如果你只使用raise,堆栈将保持不变。如果你 raise eraise Exception(e) 它将在你提出它的地方开始堆栈跟踪。
    【解决方案2】:

    这个问题没有足够的答案;-)

    这里还有一本记录簿。只需创建一个虚拟异常:

    class NeverMatch(Exception):
        'An exception class that is never raised by any code anywhere'
    

    然后,使用条件表达式来决定是否匹配真正的异常或占位符异常(永远不会引发):

    try:
        do_something(my_arg)
    except (Exception if handle_exceptions else NeverMatch) as e:
        print 'I am handling it'
    

    【讨论】:

      【解决方案3】:

      你可以使用:

      def my_func(my_arg, handle_exceptions):
        try:
          do_something(my_arg);
        except Exception as e:
          if not handle_exceptions: raise
          print "my_func is handling the exception";
      

      【讨论】:

        【解决方案4】:

        异常类型可以是变量。

        def my_func(my_arg, handle_exceptions):
          if handle_exceptions:
            exc_type = Exception
          else:
            exc_type = None
        
          try:
            do_something(my_arg);
          except exc_type, e:
            print "my_func is handling the exception";
        

        混淆 Python(“Pythonic”?)版本:

        def my_func(my_arg, handle_exceptions):
          try:
            do_something(my_arg);
          except (handle_exceptions and Exception), e:
            print "my_func is handling the exception";
        

        实际上,不带括号也可以工作,但只要我们被混淆,我们就不要用鲜为人知的规则混淆人们,比如除了语句的优先级。

        【讨论】:

          【解决方案5】:

          你总是可以抓住它并像这样有条件地重新加注:

          def my_func(my_arg, handle_exceptions):
            try:
              do_something(my_arg)
            except Exception:
              if handle_exceptions:
                print "my_func is handling the exception"
                #handle it
              else: 
                print "my_func is NOT handling the exception"
                raise
          

          【讨论】:

            【解决方案6】:

            您有两个基本选择:

            1. handle_exceptions 视为布尔值,如果False 则重新加注
            2. handle_exceptions 视为要处理的异常

            沿着布尔路径,您有两个基本选择:

            def my_func(my_arg, handle_exceptions):
                try:
                    do_something(my_arg)
                except Exception, e:
                    if not handle_exceptions:
                        raise
                    print "my_func is handling the exception"
            

            def my_func(my_arg, handle_exceptions):
                if handle_exceptions:
                    exceptions = ValueError, IndexError # or whatever
                else:
                    exceptions = NoExceptions # None in 2.x, or custom Exception class in 3.x
                try:
                    do_something(my_arg)
                except exceptions, e:
                    print "my_func is handling the exception"
            

            沿着“将handle_exceptions 视为要处理的例外”路线,您可以这样做:

            class NoExceptions(Exception):
                'Dummy exception, never raised'
            
            def my_func(my_arg, handle_exceptions=NoExceptions):
                try:
                    do_something(my_arg)
                except handle_exceptions, e:
                    print "my_func is handling the exception"
            

            你会这样称呼它:

            my_func(some_arg, ValueError)  # to handle ValueErrors
            

            my_func(some_arg)  # to not handle any exeptions
            

            这具有调用者能够指定处理哪些异常的优点/缺点。如果您确实采取了最后一条路线,您可能还想指定一个异常处理程序,可能是这样的:

            def my_func(my_arg, handle_exceptions=NoExceptions, handler=None):
                try:
                    do_something(my_arg)
                except handle_exceptions, e:
                    if handler is not None:
                        handler(e)
                    else:
                        log_this_exception()
            

            【讨论】:

              【解决方案7】:

              是的。在有意义的情况下,我更喜欢积极的条件:

              def my_func(my_arg, handle_exceptions):
                try:
                  do_something(my_arg);
                except Exception, e:
                  if handle_exceptions:
                      print "my_func is handling the exception"
                  else:
                      raise
              

              【讨论】:

                【解决方案8】:

                改进其他答案的一个漂亮的技术是将条件异常处理逻辑包装在可以重用的上下文管理器中,如下所示:

                from contextlib import contextmanager 
                
                @contextmanager
                def ignore_errors_if(exception_type, skip_condition): 
                    try: 
                        yield 
                    except exception_type, excn: 
                        if skip_condition: 
                            logging.debug("SKIPPING EXCEPTION %s" % excn)  # etc... 
                            pass 
                        else: 
                            raise excn 
                

                然后,在你的代码中,你可以说:

                def some_function(): 
                    # ... 
                    with ignore_errors_if(Exception, should_ignore_errors): 
                        result = some_funciton_that_might_raise() 
                    # Deal with result, although know that it might not be set... 
                

                【讨论】:

                  猜你喜欢
                  • 2015-05-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-03-03
                  • 1970-01-01
                  • 2019-10-02
                  • 1970-01-01
                  • 2015-02-19
                  相关资源
                  最近更新 更多