Python: Как определить цикл for для продолжения функции?

Иногда мне нужен следующий шаблон в цикле for. Время от времени более одного раза в одном цикле:

    try:
        var = 'attempt to do something that may fail on a number of levels'
    except Exception, e:
        log(e)
        continue

Теперь я не вижу приятного способа обернуть это в функцию, поскольку он не может return continue:

def attempt(this):
    try:
        return this
    except Exception, e:
        log(e)
        # 1. continue # <-- syntax error: continue not properly in loop or
        # 2. return continue # <-- invalid syntax
        # 3.
        return False # <-- this sort of works, but makes me feel powerless

Если я return False чем я мог:

    var = attempt('to do something that may fail on a number of levels')
    if not var:
        continue

Но я не чувствую, что это справедливость. Я хочу передать цикл for continue (или подделать его) из функции attempt.

Ответы

Ответ 1

У Python уже есть очень хорошая конструкция для этого, и он не использует continue:

for i in range(10):
    try:
        r = 1.0 / (i % 2)
    except Exception, e:
        print(e)
    else:
        print(r)

Я бы не стал больше гнездствовать, чем это, или ваш код скоро станет очень уродливым.

В вашем случае я, вероятно, сделаю что-то более похожее, так как намного легче unit test отдельные функции и flat лучше, чем вложенные:

#!/usr/bin/env python

def something_that_may_raise(i):
    return 1.0 / (i % 2)

def handle(e):
    print("Exception: " + str(e))

def do_something_with(result):
    print("No exception: " + str(result))

def wrap_process(i):
    try:
        result = something_that_may_raise(i)
    except ZeroDivisionError, e:
        handle(e)
    except OverflowError, e:
        handle(e) # Realistically, this will be a different handler...
    else:
        do_something_with(result)

for i in range(10):
    wrap_process(i)

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

Изменить следующие комментарии:

Если вы действительно не хотите обрабатывать исключения, которые по-прежнему считаете плохими, поймите все исключения (except:) и вместо handle(e) просто pass. На этом этапе wrap_process() закончится, пропустив else: -block, где выполняется настоящая работа, и вы перейдете к следующей итерации вашего for -loop.

Помните, Ошибки никогда не должны проходить молча.

Ответ 2

Вся идея исключений заключается в том, что они работают на нескольких уровнях косвенности, т.е. если у вас есть ошибка (или любое другое исключительное состояние) внутри вашей иерархии вызовов, вы все равно можете поймать ее на более высоком уровне и обработать ее должным образом.

В вашем случае скажем, что у вас есть попытка функции(), которая вызывает функции try2() и try3() вниз по иерархии вызовов, а try3() может столкнуться с исключительным состоянием, которое должно привести к завершению основного цикла:/p >

class JustContinueException(Exception):
    pass

for i in range(0,99):
    try:
        var = attempt() # calls attempt2() and attempt3() in turn
    except JustContinueException:
        continue # we don't need to log anything here
    except Exception, e:
        log(e)
        continue

    foo(bar)

def attempt3():
    try:
        # do something
    except Exception, e:
        # do something with e, if needed
        raise # reraise exception, so we catch it downstream

Вы даже можете сами выпустить фиктивное исключение, которое просто вызовет завершение цикла и даже не будет зарегистрировано.

def attempt3():
    raise JustContinueException()

Ответ 3

Может быть, вы хотите делать продолжение? Вы можете пойти и посмотреть, как Эрик Липперт объясняет им (если вы готовы к разуму, но на Python это может немного походить на это:

def attempt(operation, continuation):
    try:
        operation()
    except:
        log('operation failed!')
    continuation()

Внутри вашей петли вы можете сделать:

attempt(attempt_something, lambda: foo(bar)) # attempt_something is a function

Ответ 4

Подумайте, что вы отображаете foo для всех элементов, где attempt работал. Таким образом, attempt является фильтром, и его легко записать в виде генератора:

def attempted( items ):
    for item in items:
        try:
            yield attempt( item )
        except Exception, e:
            log(e)

print [foo(bar) for bar in attempted( items )]

Ответ 5

Вы можете использовать это:

for l in loop:
  attempt() and foo(bar)

но вы должны убедиться, что try() возвращает True или False.

Действительно, хотя ответ Johnsyweb, вероятно, лучше.

Ответ 6

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

Помните, что функция может возвращать tuple.

#!/usr/bin/env python

def something_that_mail_fail(i):
    failed = False
    result = None
    try:
        result = 1.0 / (i % 4)
    except:
        failed = True # But we don't care
    return failed, result

for i in range(20):
    failed, result = something_that_mail_fail(i)
    if failed:
        continue
    for rah in ['rah'] * 3:
        print(rah)
    print(result)

Я утверждаю, что try ... except ... else - это путь, и вы не должны молча игнорировать ошибки. Предостережение emptor и все такое.

Ответ 7

Помимо контекста, я просто хочу кратко ответить на вопрос. Нет, функция не может continue создать цикл, в который он может быть вызван. Это потому, что у него нет информации об этом контексте. Кроме того, это вызовет целый новый класс вопросов, например, что произойдет, если эта функция вызывается без окружающего цикла для обработки этого continue?

НО функция может сигнализировать различными способами, что она хочет, чтобы вызывающий абонент continue выполнял какой-либо цикл в настоящий момент. Разумеется, одним из способов является возвращаемое значение. Верните False или None, чтобы сигнализировать об этом, например. Другим способом сигнализации является повышение специальной Exception:

class ContinuePlease(Exception): pass

def f():
    raise ContinuePlease()

for i in range(10):
    try:
        f()
    except ContinuePlease:
        continue

Ответ 8

помещает цикл for вне try, кроме блока... simple...; -)

import sys
if '3.4' in sys.version:
    from termcolor import colored

def list_attributes (имя_модуля):   '' 'Импортируйте модуль перед вызовом этого func на it.s' ''   для индекса, метод в перечислении (dir (module_name)):       пытаться:                метод = str (метод)                module = 'email'                выражение = модуль + '.' + метод                print ('*' * len (выражение), '\n')                print (str (index).upper() + '.', color (expression.upper(), 'red'),                      ', eval (выражение). dir(),'... ','\n'2)                print ('' * len (выражение), '\n')                print (eval (выражение + '. doc'), '\n' * 4,                  'КОНЕЦ ОПИСАНИЯ ДЛЯ:' + expression.upper(), '\n' * 4)       кроме (AttributeError, NameError):           Продолжать       еще:           проходить       в конце концов:           передать

Ответ 9

Изменить: Удалил всю ту тупость, которую я сказал...

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