Могу ли я поймать ошибку в списках понимания, чтобы убедиться, что все элементы списка зациклены - PullRequest
1 голос
/ 10 февраля 2010

У меня есть списки, которые фильтруют список:

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 ]

9 голосов
/ 10 февраля 2010

Я бы использовал небольшую вспомогательную функцию:

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 голос
/ 10 февраля 2010

Пара комментариев:

Прежде всего, синтаксис понимания списка [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()
0 голосов
/ 10 февраля 2010

вы можете определить метод obj, который вызывает obj.mycond (), но также перехватывает исключение

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
0 голосов
/ 10 февраля 2010

Вместо того, чтобы копировать список и удалять элементы, начните с пустого списка и добавьте участников по мере необходимости. Примерно так:

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

Синтаксис не такой красивый, но он будет делать более или менее то же самое, что и понимание списка без ненужных удалений.

Добавление или удаление элементов в любом месте, кроме конца списка, будет медленным, поскольку при удалении чего-либо необходимо просмотреть каждый элемент, следующий за ним, и вычесть один из его индекса, и вещь для добавления чего-то, кроме того, что это нужно будет добавить в индекс. обновить положение всех элементов после него.

...