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


当前回答

Try-except-else非常适合结合EAFP模式和duck-typing:

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

您可能认为naïve代码是好的:

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

这是在代码中意外隐藏严重错误的好方法。我在那里输入了清理,但是让我知道的AttributeError正在被吞噬。更糟糕的是,如果我写对了,但清理方法偶尔被传递一个具有错误命名属性的用户类型,导致它在中途无声地失败并留下一个未关闭的文件,会怎样?祝你在调试时好运。

其他回答

也许它的用法是:

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

也许这对你也有帮助。

如果执行落在try的底部(如果没有异常),else块中的语句将被执行。说实话,我从来没有找到过需要。

然而,处理异常注意到:

使用else子句更好 而不是向try中添加额外的代码 因为它避免意外 捕获非异常 由被保护的代码引发 尝试…除了声明。

因此,如果你有一个方法,例如,抛出一个IOError,你想捕捉它引发的异常,但如果第一个操作成功,你还想做其他事情,而你不想从那个操作中捕获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()

如果您只是在operation_that_can_throw_ioerror()后面加上另一个other_operation_that_can_throw_ioerror(), except将捕获第二次调用的错误。如果你把它放在整个try块之后,它会一直运行,直到finally之后。else可以让你确定

第二次操作只有在没有例外的情况下才会进行, 它在最后一个块之前运行,并且 它引发的任何ioerror都不会在这里被捕获

假设您的编程逻辑取决于字典中是否有具有给定键的条目。你可以使用if…来测试dict.get(key)的结果。其他的……或者你可以这样做:

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

我将添加另一个用例,在处理DB会话时看起来很直接:

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

我已经找到了…Else:在运行数据库查询并将这些查询的结果记录到相同风格/类型的单独数据库的情况下,构造非常有用。假设我有很多工作线程,它们都处理提交给队列的数据库查询

#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

当然,如果您能够区分可能抛出的异常,则不必使用这种方法,但是如果代码对成功的代码段的响应可能会抛出与成功的代码段相同的异常,并且您不能让第二个可能的异常消失,或者在成功时立即返回(在我的例子中,这会杀死线程),那么这种方法就会派上用场。