Python: How to tell the for loop to continue from

2019-06-15 03:40发布

Sometimes I need the following pattern within a for loop. At times more than once in the same loop:

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

Now I don't see a nice way to wrap this in a function as it can not 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

If I return False than I could:

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

But I don't feel that does it the justice. I want to tell the for loop to continue (or fake it) from within attempt function.

9条回答
迷人小祖宗
2楼-- · 2019-06-15 04:08

Maybe you want to do continuations? You could go and look at how Eric Lippert explains them (if you are ready to have your mind blown, but in Python it could look a bit like this:

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

Inside your loop you could do:

attempt(attempt_something, lambda: foo(bar)) # attempt_something is a function
查看更多
Root(大扎)
3楼-- · 2019-06-15 04:13

Apart from the context I just want to answer the question in a brief fashion. No, a function cannot continue a loop it may be called in. That is because it has no information about this context. Also, it would raise a whole new class of questions like what shall happen if that function is called without a surrounding loop to handle that continue?

BUT a function can signal by various means that it wants the caller to continue any loop it currently performs. One means of course is the return value. Return False or None to signal this for example. Another way of signaling this is to raise a special Exception:

class ContinuePlease(Exception): pass

def f():
    raise ContinuePlease()

for i in range(10):
    try:
        f()
    except ContinuePlease:
        continue
查看更多
看我几分像从前
4楼-- · 2019-06-15 04:19

Edit: Removed all that stupidity I said...

The final answer was to rewrite the whole thing, so that I don't need to code like that.

查看更多
放我归山
5楼-- · 2019-06-15 04:20

put the for loop outside the try, except block ... simple... ;-)

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

查看更多
甜甜的少女心
6楼-- · 2019-06-15 04:21

I wouldn't normally post a second answer, but this is an alternative approach if you really don't like my first answer.

Remember that a function can return a 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)

I maintain that try ... except ... else is the way to go, and you shouldn't silently ignore errors though. Caveat emptor and all that.

查看更多
\"骚年 ilove
7楼-- · 2019-06-15 04:22

Python already has a very nice construct for doing just this and it doesn't use continue:

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

I wouldn't nest any more than this, though, or your code will soon get very ugly.

In your case I would probably do something more like this as it is far easier to unit test the individual functions and flat is better than nested:

#!/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)

Remember to always catch specific exceptions. If you were not expecting a specific exception to be thrown, it is probably not safe to continue with your processing loop.

Edit following comments:

If you really don't want to handle the exceptions, which I still think is a bad idea, then catch all exceptions (except:) and instead of handle(e), just pass. At this point wrap_process() will end, skipping the else:-block where the real work is done, and you'll go to the next iteration of your for-loop.

Bear in mind, Errors should never pass silently.

查看更多
登录 后发表回答