Python try-else

时间:2009-05-13 02:15:11

标签: python exception-handling

else声明的可选try子句的用途是什么?

22 个答案:

答案 0 :(得分:750)

else块中的语句如果执行落在try的底部,则执行 - 如果没有异常。老实说,我从来没有找到过需要。

然而,Handling Exceptions注意到:

  

使用else子句更好   而不是添加额外的代码到try   条款,因为它意外地避免   抓住一个不是的例外   由受到保护的代码引发的   试试......除了陈述。

所以,如果你有一个方法可以,例如,抛出一个IOError,你想要捕获它引发的异常,但是如果第一个操作成功,你还想做其他事情,而你< em>不想要从该操作中捕获IOError,您可以编写如下内容:

    try:
        operation_that_can_throw_ioerror()
    except IOError:
        handle_the_exception_somehow()
    else:
         # we don't want to catch the IOError if it's raised
        another_operation_that_can_throw_ioerror()
    finally:
        something_we_always_need_to_do()

如果你只是在another_operation_that_can_throw_ioerror()之后加operation_that_can_throw_ioerror,那么except会抓住第二个来电的错误。如果你把它放在整个try块之后,它将一直运行,直到finally之后。 else可让您确定

  1. 第二个操作仅在没有异常的情况下运行,
  2. 它在finally块之前运行,
  3. 任何提出的IOError都没有被抓到

答案 1 :(得分:86)

使用else时有一个的原因 - 风格和可读性。保留代码可以在代码处理它们附近引起异常通常是一个好主意。例如,比较这些:

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

except无法提前返回或重新抛出异常时,第二个是好的。如果可能的话,我会写:

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

注意:从最近发布的重复here复制的答案,因此所有这些“AskPassword”内容。

答案 2 :(得分:45)

一个用途:测试一些应引发异常的代码。

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(此代码应在实践中抽象为更通用的测试。)

答案 3 :(得分:34)

  

Python try-else

     

try语句的可选else子句的用途是什么?

摘要

如果没有例外,并且elsereturncontinue语句没有中断,break语句就会运行。

其他答案错过了最后一部分。

From the docs:

  

如果控件流出,则执行可选的else子句   try子句的结束。*

(Bolding补充道。)脚注上写着:

  

*目前,控制“流出结束”除外   异常或执行returncontinuebreak声明。

它确实需要至少一个前面的except子句(see the grammar)。所以它真的不是“尝试其他”,它是“尝试 - 除了 - 否定( - 最终)”,else(和finally)是可选的。

Python Tutorial详细说明了预期用途:

  

try ... except语句有一个可选的else子句,当时   礼物,必须遵循除了条款以外的所有条款它对代码很有用   如果try子句没有引发异常,则必须执行。对于   例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()
     

使用else子句比添加其他代码要好   try子句,因为它避免意外捕获异常   这个代码不受try的保护而引发...除外   言。

区分elsetry

之后的代码的示例

如果处理错误,else块将无法运行。例如:

def handle_error():
    try:
        raise RuntimeError('oops!')
    except RuntimeError as error:
        print('handled a RuntimeError, no big deal.')
    else:
        print('if this prints, we had no error!') # won't print!
    print('And now we have left the try block!')  # will print!

现在,

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!

答案 4 :(得分:16)

Try-except-else非常适合将the EAFP patternduck-typing结合使用:

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

你可能认为这个天真的代码很好:

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

这是在代码中意外隐藏严重错误的好方法。我在那里进行了错误的清理,但是让我知道的AttributeError被吞没了。更糟糕的是,如果我写得正确怎么办,但是清理方法偶尔会传递一个具有错误名称属性的用户类型,导致它在中途无声地失败并保持文件未闭合?祝你好好调试一下。

答案 5 :(得分:14)

我发现即使有例外,你必须要做清理才真的有用:

try:
    data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
    handle_exception(e)
else:
    do_stuff(data)
finally:
    clean_up()

答案 6 :(得分:10)

即使您现在无法想到它的使用,您也可以打赌必须使用它。这是一个缺乏想象力的样本:

使用else

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something

没有else

try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

如果没有抛出错误,您可以在此处定义变量something。您可以在try块之外删除它,但如果定义了变量,则需要进行一些混乱的检测。

答案 7 :(得分:8)

来自Errors and Exceptions # Handling exceptions - docs.python.org

  

try ... except语句有一个可选的else子句,   在场的时候,必须遵循所有除了条款。它对代码很有用   如果try子句没有引发异常,则必须执行该操作。   例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()
     

使用else子句比添加其他代码要好   try子句,因为它避免意外捕获异常   这个代码不受try的保护而引发...除外   言。

答案 8 :(得分:6)

PEP 380中有try-else的好例子。基本上,它归结为在算法的不同部分进行不同的异常处理。

这是这样的:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

这允许您编写更接近异常发生位置的异常处理代码。

答案 9 :(得分:5)

查看Python reference似乎elsetry之后执行时没有异常。 如果控制流出try子句的末尾,则执行可选的else子句。 2 else子句中的异常不由前面的except子句处理。

Dive into python有一个例子,如果我理解正确的话,在try块中他们会尝试导入一个模块,当失败时你得到异常并绑定默认值但是当它工作时你可以选择进入else块并绑定所需内容(请参阅示例和说明的链接)。

如果你试图在catch块中工作,它可能会抛出另一个异常 - 我想这就是else块可以派上用场的地方。

答案 10 :(得分:3)

大多数答案似乎都集中在为什么我们不能将材料放在try子句本身的else子句中。问题else clause in try statement... what is it good for特别询问为什么else子句代码不能在 try块本身之后,并且该问题被重复到这个问题,但我在这里看不到对该问题的明确答复。我觉得https://stackoverflow.com/a/3996378/1503120出色地回答了这个问题。我还试图在https://stackoverflow.com/a/22579805/1503120阐明各种条款的各种重要性。

答案 11 :(得分:3)

就是这样。 try-except子句的'else'块存在于尝试的操作成功时(且仅当)尝试运行的代码。它可以使用,也可以被滥用。

try:
    fp= open("configuration_file", "rb")
except EnvironmentError:
    confdata= '' # it's ok if the file can't be opened
else:
    confdata= fp.read()
    fp.close()

# your code continues here
# working with (possibly empty) confdata

就个人而言,我喜欢并在适当的时候使用它。它在语义上对语句进行分组。

答案 12 :(得分:2)

也许用途可能是:

#debug = []

def debuglog(text, obj=None):
    " Simple little logger. "
    try:
        debug   # does global exist?
    except NameError:
        pass    # if not, don't even bother displaying
    except:
        print('Unknown cause. Debug debuglog().')
    else:
        # debug does exist.
        # Now test if you want to log this debug message
        # from caller "obj"
        try:
            if obj in debug:
                print(text)     # stdout
        except TypeError:
            print('The global "debug" flag should be an iterable.')
        except:
            print('Unknown cause. Debug debuglog().')

def myfunc():
    debuglog('Made it to myfunc()', myfunc)

debug = [myfunc,]
myfunc()

也许这会让你过度使用。

答案 13 :(得分:1)

这是另一个我喜欢使用这种模式的地方:

 while data in items:
     try
        data = json.loads(data)
     except ValueError as e:
        log error
     else:
        # work on the `data`

答案 14 :(得分:1)

我发现else对于处理可能不正确的配置文件非常有用:

try:
    value, unit = cfg['lock'].split()
except ValueError:
    msg = 'lock monitoring config must consist of two words separated by white space'
    self.log('warn', msg)
else:
     # get on with lock monitoring if config is ok

读取lock配置的异常会禁用锁定监控,而ValueErrors会记录一条有用的警告消息。

答案 15 :(得分:1)

通常可以存在else块,以补充每个except块中发生的功能。

try:
    test_consistency(valuable_data)
except Except1:
    inconsistency_type = 1
except Except2:
    inconsistency_type = 2
except:
    # Something else is wrong
    raise
else:
    inconsistency_type = 0

"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""

在这种情况下,在每个除了块之外设置inconsistency_type,以便在else中的无错误情况下补充该行为。

当然,我将此描述为一种模式,有一天可能会出现在您自己的代码中。在这种特定情况下,您只需在inconsistency_type块之前将try设置为0。

答案 16 :(得分:1)

我发现try: ... else:构造在运行数据库查询并将这些查询的结果记录到具有相同flavor / type的单独数据库的情况下非常有用。假设我有很多工作线程都处理提交到队列的数据库查询

#in a long running loop
try:
    query = queue.get()
    conn = connect_to_db(<main db>)
    curs = conn.cursor()
    try:
        curs.execute("<some query on user input that may fail even if sanitized">)
    except DBError:
        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of failed query")
        logcurs.close()
        logconn.close()
    else:

        #we can't put this in main try block because an error connecting
        #to the logging DB would be indistinguishable from an error in 
        #the mainquery 

        #We can't put this after the whole try: except: finally: block
        #because then we don't know if the query was successful or not

        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of successful query")
        logcurs.close()
        logconn.close()
        #do something in response to successful query
except DBError:
    #This DBError is because of a problem with the logging database, but 
    #we can't let that crash the whole thread over what might be a
    #temporary network glitch
finally:
    curs.close()
    conn.close()
    #other cleanup if necessary like telling the queue the task is finished

当然,如果您可以区分可能引发的异常,则不必使用它,但如果代码对成功的代码做出反应可能会抛出与成功代码相同的异常,那么您可以不要让第二个可能的例外,或者在成功时立即返回(这会在我的情况下杀死线程),然后这确实派上用场了。

答案 17 :(得分:1)

假设您的编程逻辑取决于字典是否具有给定键的条目。您可以使用dict.get(key)构造测试if... else...的结果,或者您可以执行以下操作:

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)

答案 18 :(得分:1)

我能想到的其中一个使用场景是不可预测的异常,如果再试一次可以绕过这些异常。例如,当try块中的操作涉及随机数时:

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

但是如果可以预测异常,则应始终事先选择验证异常。但是,并非所有内容都可以预测,因此这种代码模式就有了它的位置。

答案 19 :(得分:1)

try:
    statements # statements that can raise exceptions
except:
    statements # statements that will be executed to handle exceptions
else:
    statements # statements that will be executed if there is no exception

示例:

try:
    age=int(input('Enter your age: '))
except:
    print ('You have entered an invalid value.')
else:
    if age <= 21:
        print('You are not allowed to enter, you are too young.')
    else:
        print('Welcome, you are old enough.')

输出:

>>> 
Enter your age: a
You have entered an invalid value.
>>> RESTART
>>> 
Enter your age: 25
Welcome, you are old enough.
>>>RESTART
>>> 
Enter your age: 13
You are not allowed to enter, you are too young.
>>>

复制自:https://geek-university.com/python/the-try-except-else-statements/

答案 20 :(得分:0)

我将添加另一个在处理数据库会话时似乎很简单的用例:

    # getting a DB connection 
    conn = db.engine.connect()

    # and binding to a DB session
    session = db.get_session(bind=conn)

    try:
        # we build the query to DB
        q = session.query(MyTable).filter(MyTable.col1 == 'query_val')

        # i.e retrieve one row
        data_set = q.one_or_none()

        # return results
        return [{'col1': data_set.col1, 'col2': data_set.col2, ...}]

    except:
        # here we make sure to rollback the transaction, 
        # handy when we update stuff into DB
        session.rollback()
        raise

    else:
        # when no errors then we can commit DB changes
        session.commit()

    finally:
        # and finally we can close the session
        session.close()

答案 21 :(得分:-16)

else:区块令人困惑,而且(几乎)无用。它也是forwhile语句的一部分。

实际上,即使在if语句中,else:也可能以非常糟糕的方式被滥用,从而产生很难找到的错误。

考虑一下。

   if a < 10:
       # condition stated explicitly
   elif a > 10 and b < 10:
       # condition confusing but at least explicit
   else:
       # Exactly what is true here?
       # Can be hard to reason out what condition is true

else:三思而后行。这通常是个问题。除了if - 语句之外,请避免使用它,甚至考虑记录else - 条件以使其明确。