1

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

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

在这篇文章中(如何在不重复的情况下循环列表本身时删除列表元素)我问是否有更好的方法来循环避免列表重复。

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

您认为有替代解决方案吗?我可以使用列表推导以这种方式管理异常吗?在这种情况下并使用大列表(我必须考虑什么大?)我必须找到另一种选择吗?

4

4 回答 4

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' 类进行任何更改,代码的整体结构非常简单。

于 2010-02-10T04:08:08.357 回答
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()
于 2010-02-10T02:29:25.557 回答
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

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

向列表末尾以外的任何地方添加或删除元素会很慢,因为当您删除某些内容时,它需要遍历它之后的每个项目并从其索引中减去一个,并且添加除它之外的其他内容也是如此'将需要添加到索引中。更新其后所有元素的位置。

于 2010-02-10T02:22:50.187 回答
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
于 2010-02-10T02:29:17.993 回答