python - 在其消费者中处理生成器异常

标签 python exception-handling generator

这是 Handle an exception thrown in a generator 的后续事件并讨论一个更普遍的问题。

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

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 block 中,但事实证明,这是行不通的。所以我必须将 try-except 添加到 parsefunc 本身,然后以某种方式将异常传递给消费者:

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

我不太愿意这样做,因为

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

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

google人注意事项:除了置顶答案,关注senderle'sJon's帖子 - 非常聪明和有见地的东西。

最佳答案

你可以在 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

关于python - 在其消费者中处理生成器异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11366892/

相关文章:

php - 在 PHP 中重新抛出异常是否会破坏堆栈跟踪?

javascript - 在 Koa 发送响应后运行代码

python - python -m unittest 执行什么功能?

python - 在创建实体后向 webapp2 用户模型添加用户名属性(使用 Simpleauth)

Python:从导入的模块中获取导入模块的详细信息

python-3.x - 在 Python 中正确实现 Shutil.Error

c++ - D3D12CreateDevice 抛出 _com_error

python - Django - 无法使用 View 功能将新条目保存到数据库

java - 有没有字节码的java代码生成器

javascript - Promise.all 对遍历生成器无效