25

有时我需要在for循环中使用以下模式。有时在同一个循环中不止一次:

try:
    # attempt to do something that may diversely fail
except Exception as e:
    logging.error(e)
    continue

现在我看不到将其包装在函数中的好方法,因为它不能return continue

def attempt(x):
    try:
        raise random.choice((ValueError, IndexError, TypeError))
    except Exception as e:
        logging.error(e)
        # continue  # syntax error: continue not properly in loop
        # return continue  # invalid syntax
        return None  # this sort of works

如果return None我能:

a = attempt('to do something that may diversely fail')
if not a:
    continue

但我不觉得这样做是正义的。我想continueattempt函数内部告诉 for 循环(或伪造它)。

4

9 回答 9

15

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:实际工作完成的 -block,然后您将进入for-loop 的下一次迭代。

请记住,错误永远不应该悄无声息地过去

于 2011-05-20T11:19:36.820 回答
8

异常的整个想法是它们跨多个间接级别工作,即,如果您在调用层次结构深处有错误(或任何其他异常状态),您仍然可以在更高级别上捕获它并正确处理它。

在您的情况下,假设您有一个函数尝试(),它在调用层次结构中调用函数尝试2()和尝试3(),并且尝试3()可能会遇到异常状态,这应该导致主循环终止:

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()
于 2011-05-20T11:30:52.670 回答
3

也许你想做延续?你可以去看看Eric Lippert 是如何解释它们的(如果你准备好大吃一惊,但在 Python 中它可能看起来有点像这样:

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

在您的循环中,您可以执行以下操作:

attempt(attempt_something, lambda: foo(bar)) # attempt_something is a function
于 2011-05-20T11:30:49.303 回答
3

除了上下文,我只想简短地回答这个问题。不,一个函数不能continue循环调用它。那是因为它没有关于这个上下文的信息。此外,它会引发一类全新的问题,例如如果调用该函数而没有周围的循环来处理会发生continue什么?

但是一个函数可以通过各种方式发出信号,表明它希望调用者进入continue它当前执行的任何循环。一种方法当然是返回值。例如,返回FalseNone发出信号。另一种表示这一点的方法是提出一个特殊的Exception

class ContinuePlease(Exception): pass

def f():
    raise ContinuePlease()

for i in range(10):
    try:
        f()
    except ContinuePlease:
        continue
于 2012-09-05T08:57:47.770 回答
2

你可以使用这个:

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

但是您应该确保尝试()返回 True 或 False。

不过,确实,Johnsyweb 的答案可能更好。

于 2011-05-20T11:30:22.583 回答
2

认为您正在映射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 )]
于 2011-05-20T13:52:04.633 回答
1

我通常不会发布第二个答案,但如果您真的不喜欢我的第一个答案,这是一种替代方法。

请记住,函数可以返回一个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是要走的路,但你不应该默默地忽略错误。警告购买者和所有这些。

于 2011-05-21T00:15:45.453 回答
0

在try之外尝试for循环,除了block

这个答案考虑了 Python 3.4,但是在新版本中有更好的方法。这是我的建议

导入系统
如果 sys.version 中的“3.4”:
    从 termcolor 导入有色

def list_attributes(module_name): '''在调用这个函数之前导入模块。s''' 对于索引,枚举中的方法(dir(module_name)): 尝试: 方法 = str(方法) 模块 = '电子邮件' 表达式 = 模块 + '.' + 方法 print('*' * len(表达式), '\n') print(str(index).upper() + '.',colored(expression.upper(), 'red'), ' ',评估(表达式)。目录() , '...' , '\n' 2 ) print(' ' * len(表达式), '\n') print( eval( 表达式 + ' .doc ' ), '\n'*4, '描述结束:' + expression.upper(), '\n'*4) 除了(AttributeError,NameError): 继续 别的: 经过 最后: 经过

于 2014-11-27T00:47:08.867 回答
-4

编辑:删除了我说的所有愚蠢...

最后的答案是重写整个事情,这样我就不需要那样编码了。

于 2011-05-21T13:59:14.497 回答