Python 嵌套尝试除了 vs if、elif、else

Python nested try except vs if, elif, else

我正在尝试熟悉 Python 的最佳实践。根据 Python 的禅宗,请求宽恕比请求许可更容易,但是,它也说平面优于嵌套和可读性。你会如何处理这个问题:

我有3本词典。我有一把钥匙,我想测试钥匙是否在字典中。钥匙只会在其中之一。根据它所在的字典,我想做不同的事情。

使用try/except,我得出以下解决方案:

try:
    val = dict1[key]
except KeyError:
    try:
        val = dict2[key]
    except KeyError:
        try:
            val = dict3[key]
        except KeyError:
            do_stuff_key_not_found()
        else:
            do_stuff_dict3()
    else:
        do_stuff_dict2()
else:
    do_stuff_dict1()

根据 Python 的 EAFP 原则,这将是可行的方法,但它看起来很杂乱,而且可读性不是很好。

一个更简单的解决方案是:

if key in dict1:
    val = dict1[key]
    do_stuff_dict1()
elif key in dict2:
    val = dict2[key]
    do_stuff_dict2()
elif key in dict3:
    val = dict3[key]
    do_stuff_dict3()
else:
    do_stuff_key_not_found()

处理这种情况更Pythonic的方法是什么?我应该坚持 EAFP 原则,还是扁平化和可读性更重要?

EAFP 在很多情况下都是一个合理的格言,但它不是一个可以盲目遵循的格言。在你的例子中,我会说 if/elif 版本没有什么可怕的错误。

这两个版本都涉及代码重复,因此如果您要处理大量情况,可能会变得笨拙。一种处理方法是将 dict/function 对拉出到一个列表中,然后遍历该列表:

handlers = [ (dict1, do_stuff_dict1), (dict2, do_stuff_dict2), (dict3, do_stuff_dict3) ]
for whichDict, whichFunc in handlers:
    try:
        val = whichDict[key]
    except KeyError:
        continue
    else:
        whichFunc()
        break
else:
    do_stuff_not_found()

我更喜欢使用 dict.get(key, default_value) 来避免异常处理,例如:

handlers = [(d1, func_1), (d2, func_2)]
handlers_found = [(d, func) for d, func in handlers if d.get(key)]
if handlers_found:
    handlers_found[0][1]()
else:
    do_stuff_not_found()

get(key[, default]) Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError. https://docs.python.org/2/library/stdtypes.html