一尘不染

在使用者中处理生成器异常

python

这是处理生成器中引发的异常的后续操作,并讨论了一个更一般的问题。

我有一个功能,可以读取不同格式的数据。所有格式都是面向行或记录的,每种格式都有一个专用的解析功能,可以作为生成器来实现。因此,主读取函数获得一个输入和一个生成器,该生成器从输入中读取其各自的格式并将记录传递回主函数:

def read(stream, parsefunc):
    for record in parsefunc(stream):
        do_stuff(record)

哪里parsefunc是这样的:

def parsefunc(stream):
    while not eof(stream):
        rec = read_record(stream)
        do some stuff
        yield rec

我面临的问题是,尽管parsefunc可能引发异常(例如,从流中读取时),但它不知道如何处理它。负责处理异常的read功能是主要功能。请注意,异常是基于每个记录发生的,因此,即使一个记录失败,生成器也应继续其工作并产生记录,直到整个流耗尽为止。

在上一个问题中,我试图放next(parsefunc)一个try段落,但事实证明,这是行不通的。所以,我必须添加try- exceptparsefunc自身,然后以某种方式提供例外的消费者:

def parsefunc(stream):
    while not eof(stream):
        try:
            rec = read_record()
            yield rec
        except Exception as e:
            ?????

我不太愿意这样做,因为

  • try在不打算处理任何异常的函数中使用没有意义
  • 我不清楚如何将异常传递给使用函数
  • 会有许多格式和许多格式parsefunc,我不想用太多的辅助代码来使它们混乱。

有没有人建议更好的架构?


阅读 115

收藏
2020-12-20

共1个答案

一尘不染

您可以在parsefunc中返回记录和异常的元组,并让使用者函数决定如何处理异常:

import random

def get_record(line):
  num = random.randint(0, 3)
  if num == 3:
    raise Exception("3 means danger")
  return line


def parsefunc(stream):
  for line in stream:
    try:
      rec = get_record(line)
    except Exception as e:
      yield (None, e)
    else:
      yield (rec, None)

if __name__ == '__main__':
  with open('temp.txt') as f:
    for rec, e in parsefunc(f):
      if e:
        print "Got an exception %s" % e
      else:
        print "Got a record %s" % rec
2020-12-20