忽略生成器的异常

时间:2014-12-23 03:19:17

标签: python exception for-loop generator

使用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生成器,如何捕获其中的异常?

3 个答案:

答案 0 :(得分:4)

<强>更新

我原本以为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:

您应该始终尝试捕捉最具体的例外情况。否则,您将冒着意外捕获您不想处理的异常的风险。

答案 1 :(得分:0)

在使用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。

答案 2 :(得分:-2)

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