【问题标题】:Ignore exception from generator忽略来自生成器的异常
【发布时间】:2014-12-23 03:19:16
【问题描述】:

通过使用os.walk() 像这样遍历文件夹:

for subdir, dirs, files in os.walk(path):
    do something...

会抛出异常:UnicodeDecodeError,我想忽略异常继续,我试过这个:

try:
    for subdir, dirs, files in os.walk(path):
        do something...
except Exception, e:
    logging.exception(e)
    continue   # this continue is illegal

正如评论所说,异常部分中的continue 是语法错误。有没有办法忽略异常继续遍历?

异常是从os.walk()抛出的,所以把try/except放在for里面是不能捕获异常的。 os.walk() 将返回一个python 生成器,如何在其中捕获异常?

【问题讨论】:

    标签: python exception for-loop generator


    【解决方案1】:

    更新:

    我最初认为错误是由do something... 代码引发的。由于它实际上是由os.walk 提出的,因此您需要做一些不同的事情:

    walker = os.walk(path)
    while True:
        try:
            subdir, dirs, files = next(walker)
        except UnicodeDecodeError as e:
            logging.exception(e)
            continue
        except StopIteration:
            break
    
        do something...
    

    基本上,这是利用os.walk 返回generator object 的事实。这允许我们在其上调用next,从而控制每一步的迭代。

    subdir, dirs, files = next(walker) 行尝试推进迭代。如果引发了UnicodeDecodeError,它会被记录下来,然后我们继续下一步。如果引发StopIteration 异常,则意味着我们已经完成了对目录树的遍历。所以,我们打破循环。


    由于continue 需要在循环内,您还需要将try/except 块移到其中:

    for subdir, dirs, files in os.walk(path):
        try:
            do something...
        except Exception, e:
            logging.exception(e)
            continue   # this continue is *not* illegal
    

    另外,做:

    except Exception, e:
    

    已被弃用。您应该使用 as 关键字代替 ,

    except Exception as e:
    

    当您使用它时,您应该将通用的Exception 替换为特定的UnicodeDecodeError

    except UnicodeDecodeError as e:
    

    您应该始终尝试捕获最具体的异常。否则,您可能会意外捕捉到您无意处理的异常。

    【讨论】:

    • 也更好地捕捉特定的 UnicodeDecodeError 而不是任何一般的异常“做某事”可能会引发。
    • os.walk() 抛出的异常不在for 循环内,所以try/except 对该异常不做任何事情。
    【解决方案2】:

    我在使用 Beautiful Soup 迭代链接时遇到了类似的情况。这是我为此编写的代码:

    class suppressed_iterator:
        def __init__(self, wrapped_iter, skipped_exc = Exception):
            self.wrapped_iter = wrapped_iter
            self.skipped_exc  = skipped_exc
    
        def __next__(self):
            while True:
                try:
                    return next(self.wrapped_iter)
                except StopIteration:
                    raise
                except self.skipped_exc:
                    pass
    
    class suppressed_generator:
        def __init__(self, wrapped_obj, skipped_exc = Exception):
            self.wrapped_obj = wrapped_obj
            self.skipped_exc = skipped_exc
    
        def __iter__(self):
            return suppressed_iterator(iter(self.wrapped_obj), self.skipped_exc)
    

    一个例子:

    class IHateThirteen:
        ''' Throws exception while iterating on value 13 '''
    
        def __init__(self, iterable):
            self.it = iter(iterable)
    
        def __iter__(self):
            return self
    
        def __next__(self):
            v = next(self.it)
            if v == 13:
                raise ValueError('I hate 13!')
            return v
    
    # Outputs [10, 11, 12, 14, 15]
    exception_at_thirteen = IHateThirteen([10, 11, 12, 13, 14, 15])
    print(list(suppressed_generator(exception_at_thirteen)))
    
    # Raises ValueError
    exception_at_thirteen = IHateThirteen([10, 11, 12, 13, 14, 15])
    print(list(exception_at_thirteen))
    

    您可以使用上面的代码来修复您的代码:

    for subdir, dirs, files in suppressed_generator(os.walk(path)):
        do something...
    

    如果需要,上面的代码可以扩展为每个跳过的异常类型都有回调,但在这种情况下使用iCodez's answer 可能更符合pythonic。

    【讨论】:

      【解决方案3】:
      for subdir, dirs, files in os.walk(path):
          try:
              do something...
          except Exception, e:
              logging.exception(e)
              continue   # this continue is illegal
      

      【讨论】:

      • 这不回答任何问题,它只是从原始问题中复制一段代码。
      猜你喜欢
      • 2013-09-09
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 2011-03-13
      • 1970-01-01
      • 2022-06-16
      • 2010-11-20
      相关资源
      最近更新 更多