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 (или фейк) внутри

9 ответов


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

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

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

в вашем случае я бы, вероятно, сделал что-то более подобное, так как гораздо проще тестировать отдельные функции и 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:-блок, где реальная работа делается, и вы пойдете к следующей итерации for-loop.

имейте в виду, ошибки никогда не должны пройти молча.


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

в вашем случае, скажем, у вас есть функция attempt (), которая вызывает функции attempt2 () и attempt3() вниз по иерархии вызовов, и attempt3 () может столкнуться с исключительным состоянием, которое должно вызвать основной цикл прекратить:

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()

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

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

внутри вашего цикла, вы могли бы сделать:

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

думаю, что вы сопоставляете 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 )]

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

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

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

на самом деле, однако, ответ Johnsyweb, вероятно, лучше.


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

помните, что функция может возвращать 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 и все такое.


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

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

class ContinuePlease(Exception): pass

def f():
    raise ContinuePlease()

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

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

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

def list_attributes(module_name): '''Import the module before calling this func on it.s ''' for index, method in enumerate(dir(module_name)): try: method = str(method) module = 'email' expression = module + '.' + method print('*' * len(expression), '\n') print( str(index).upper() + '. ',colored( expression.upper(), 'red'), ' ', eval( expression ).dir() , '...' , '\n'2 ) print('' * len(expression), '\n') print( eval( expression + '.doc' ), '\n'*4, 'END OF DESCRIPTION FOR: ' + expression.upper(), '\n'*4) except (AttributeError, NameError): continue else: pass finally: pass


Edit: удалил всю эту глупость, которую я сказал...

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