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


当前回答

使用else样式和可读性是一个重要原因。将可能导致异常的代码放在处理异常的代码附近通常是个好主意。例如,比较这些:

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

and

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

当异常不能提前返回或重新抛出异常时,第二个方法很好。如果可能的话,我会这样写:

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

# 20 other lines
getpass = AskPassword

注意:答案从最近发布的副本复制在这里,因此所有这些“AskPassword”的东西。

其他回答

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

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

但是如果可以预测异常,则应该始终在异常之前选择验证。然而,并不是所有的事情都可以预测,所以这种代码模式有它的一席之地。

PEP 380中有一个很好的try-else示例。基本上,它归结为在算法的不同部分做不同的异常处理。

大概是这样的:

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

这允许您在异常发生的地方编写异常处理代码。

也许它的用法是:

#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:
    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

读取锁配置的异常禁用锁监控,ValueErrors记录有用的警告消息。

我已经找到了…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

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