清理嵌套的Try/Except

4 投票
4 回答
1396 浏览
提问于 2025-04-15 12:51

我刚写了一段代码,感觉它的嵌套层次太多了,不太理想。我想请教一下,怎么才能让这段代码的风格更好,特别是让它更符合“扁平化比嵌套好”的原则。

for app in apps:
    if app.split('.', 1)[0] == 'zc': #only look for cron in zc apps
        try:
            a = app + '.cron'
            __import__(a)
            m = sys.modules[a]

            try:
                min = m.cron_minute()
                for job in min:
                    k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                        60*job[1], 
                                        kronos.method.threaded, (), ())
            except AttributeError: #no minute tasks
                pass

            try:
                hour = m.cron_hour()
                for job in hour:
                    k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                                       (job[1], r(H_LB, H_UB)), 
                                       kronos.method.threaded, (), ())
            except AttributeError: #no hour tasks
                pass

        except ImportError: #no cron jobs for this module
            pass

编辑:结合下面的建议,这是我重新写的版本。

for app in apps:
    if app.split('.', 1)[0] != 'zc': #only look for cron in zc apps
        continue

    try:
        a = app + '.cron'
        __import__(a)
    except ImportError: #no cron jobs for this module, continue to next one
        continue

    m = sys.modules[a]
    if hasattr(m, 'cron_minute'):
        min = m.cron_minute()
        for job in min:
            k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                60*job[1], 
                                kronos.method.threaded, (), ())

    if hasattr(m, 'cron_hour'):
        hour = m.cron_hour()
        for job in hour:
            k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                               (job[1], r(H_LB, H_UB)), 
                               kronos.method.threaded, (), ())

4 个回答

0

这里的关键是要弄清楚它们是否出错了。这就是异常处理中的处理部分。我的意思是,至少要打印一个警告,说明评论的假设是什么。在实际处理之前就担心过多的嵌套,感觉有点超前了。先关注处理是否正确,再考虑其他的花样。

1

我在想,如果每个时间单位的任务真的出现了问题,会不会引发一个属性错误(AttributeError)或者其他的异常呢?特别是,如果某个任务真的坏掉了,你可能就不应该去捕捉这些错误。

还有一个可以帮助你的方法是,只对出问题的代码块使用try-catch,也就是把错误处理的代码放得尽量靠近出错的地方。这里有个例子:

for app in apps:
    if app.split('.', 1)[0] == 'zc': #only look for cron in zc apps
        try:
            a = app + '.cron'
            __import__(a)
            m = sys.modules[a]
        except ImportError: #no cron jobs for this module
                            #exception is silently ignored
                            #since no jobs is not an error
            continue
        if hasattr(m, "cron_minute"):
            min = m.cron_minute()
            for job in min:
                k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                    60*job[1], 
                                    kronos.method.threaded, (), ())

        if hasattr(m, "cron_hour"):
            hour = m.cron_hour()
            for job in hour:
                k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                                   (job[1], r(H_LB, H_UB)), 
                                   kronos.method.threaded, (), ())

注意这里只有一个错误处理器,我们通过正确地忽略它来处理这个问题。因为我们可以预测到可能会缺少某个属性,所以我们明确地检查一下,这样可以让代码看起来更清晰。否则,你就不太明白为什么要捕捉这个属性错误,或者到底是什么导致了这个错误。

8

主要问题是你的try语句写得太宽泛了,特别是最外层的那一个。这样写的话,迟早会遇到一些神秘的错误,因为你的某个try/except可能会意外地把其他函数抛出的异常给隐藏掉了。

所以我建议你可以这样做:

for app in apps:
    if app.split('.', 1)[0] != 'zc': #only look for cron in zc apps
        continue

    try:
        a = app + '.cron'
        __import__(a)
    except ImportError: #no cron jobs for this module
        continue

    # etc etc

顺便提一下,我在另一个方面也在应用“扁平化比嵌套好”的原则(这和try/except没有关系),就是“如果我在这个循环的这一段没有其他事情要做,就继续(也就是跳到下一个循环)”,而不是“如果我有事情要做:”后面跟着一大堆嵌套的代码。我一直更喜欢这种风格(用if/continue或if/return)而不是嵌套的if,这在现代编程语言中都能找到类似的功能,比如continue(几乎所有现代语言都有,因为C语言就有这个功能;-)。

不过这只是一个简单的“扁平化与嵌套”的风格偏好,真正的问题是:保持你的try语句简短!最糟糕的情况是,当你在except语句中无法简单地继续或返回时,可以使用try/except/else:在try语句中只放入那些绝对必须的代码——也就是那些很可能会抛出异常的小段代码——而把后面的其他代码(那些不应该也不期待抛出异常的部分)放在else语句中。这并不会改变嵌套的结构,但确实能大大降低意外隐藏不该被隐藏的异常的风险!

撰写回答