我可以在列表推导中捕获错误,以确保循环所有列表项

时间:2010-02-10 02:14:08

标签: python exception list cycle

我有一个列表推导过滤列表:

l = [obj for obj in objlist if not obj.mycond()]

但是对象方法mycond()可以引发一个我必须拦截的异常。我需要在循环结束时收集所有错误,以显示哪个对象创建了任何问题,同时我想确保循环所有列表元素。

我的解决方案是:

errors = []
copy = objlist[:]

for obj in copy:
    try:
        if (obj.mycond()):
            # avoiding to touch the list in the loop directly
            objlist.remove(obj) 
    except MyException as err:
        errors = [err]
if (errors):
   #do something

return objlist

在这篇文章(How to delete list elements while cycling the list itself without duplicate it)中,我问是否有更好的方法来循环避免列表重复。

社区回答我,以避免列表修改,并使用适用的列表推导,如果我忽略异常问题。

您的观点是否有替代解决方案?我可以使用列表推导以这种方式管理异常吗?在这种情况下并使用大名单(我必须考虑哪些大?)我必须找到另一种选择吗?

4 个答案:

答案 0 :(得分:9)

我会使用一点辅助功能:

def f(obj, errs):
  try: return not obj.mycond()
  except MyException as err: errs.append((obj, err))

errs = []
l = [obj for obj in objlist if f(obj, errs)]
if errs:
  emiterrorinfo(errs)

请注意,这样您在errs所有错误对象中都有与其相对应的特定异常,因此诊断可以准确完整;以及您需要的l,以及您的objlist仍然完好无损,以便进一步使用。不需要列表副本,也不需要对obj类进行任何更改,代码的整体结构非常简单。

答案 1 :(得分:1)

几条评论:

首先,列表推导语法[expression for var in iterable]可以创建副本。如果您不想创建列表的副本,请使用生成器表达式(expression for var in iterable)

发电机如何工作?基本上通过反复调用对象上的next(obj),直到引发GeneratorExit异常。

根据您的原始代码,您似乎仍然需要将过滤后的列表作为输出。

所以你可以效仿,但性能损失很小:

l = []
for obj in objlist:
   try:
      if not obj.mycond()
         l.append(obj)
   except Exception:
      pass

但是,您可以使用生成器功能重新设计所有这些:

def FilterObj(objlist):
   for obj in objlist:
      try:
         if not obj.mycond()
            yield obj
      except Exception:
         pass

通过这种方式,您可以安全地迭代它,而不会在此期间缓存列表:

for obj in FilterObj(objlist):
   obj.whatever()

答案 2 :(得分:0)

不是复制列表和删除元素,而是从空白列表开始,并根据需要添加成员。像这样:

errors = []
newlist = []

for obj in objlist:
    try:
        if not obj.mycond():
            newlist.append(obj)
    except MyException as err:
        errors.append(err)
if (errors):
   #do something

return newlist

语法不是那么漂亮,但它或多或少与列表推导相同,没有任何不必要的删除。

在列表末尾以外的任何位置添加或删除元素都会很慢,因为当你删除某些东西时,它需要遍历它后面的每个项目并从索引中减去一个,并且相同添加东西的东西,除了它需要添加到索引。更新后面的所有元素的位置。

答案 3 :(得分:0)

你可以定义一个调用obj.mycond()但也捕获异常的obj方法

class obj:

    def __init__(self):
        self.errors = []

    def mycond(self):
        #whatever you have here

    def errorcatcher():
        try:
            return self.mycond()
        except MyException as err:
            self.errors.append(err)
            return False # or true, depending upon what you want

l = [obj for obj in objlist if not obj.errorcatcher()]

errors = [obj.errors for obj in objlist if obj.errors]

if errors:
    #do something