在python中嵌套的try / except块是一个很好的编程习惯吗?

时间:2013-06-09 23:37:30

标签: python

我正在编写自己的容器,需要通过属性调用来访问内部的字典。容器的典型用法是这样的:

dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo

我知道写这样的东西可能是愚蠢的,但这是我需要提供的功能。我正在考虑以下列方式实现这一点:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        try:
            return self.dict[item]
        except KeyError:
            print "The object doesn't have such attribute"

我不确定嵌套的try / except块是否是一个好习惯,另一种方法是使用hasattr()has_key()

def __getattribute__(self, item):
        if hasattr(self, item):
            return object.__getattribute__(item)
        else:
            if self.dict.has_key(item):
                return self.dict[item]
            else:
                raise AttributeError("some customised error")

或者使用其中一个和一个尝试catch块,如下所示:

def __getattribute__(self, item):
    if hasattr(self, item):
        return object.__getattribute__(item)
    else:
        try:
            return self.dict[item]
        except KeyError:
            raise AttributeError("some customised error")

哪个选项最诡异和优雅?

11 个答案:

答案 0 :(得分:134)

你的第一个例子非常好。即使是官方的Python文档也推荐使用这种称为EAFP的方式。

就个人而言,我更愿意在没有必要时避免嵌套:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass  # fallback to dict
    try:
        return self.dict[item]
    except KeyError:
        raise AttributeError("The object doesn't have such attribute") from None

PS。 {2}已在Python 2中弃用has_key()。请改用item in self.dict

答案 1 :(得分:14)

虽然在Java中使用Exceptions进行流控制确实是一种不好的做法(主要是因为异常迫使jvm收集资源(more here)),但在Python中你有两个重要的原则:Duck TypingEAFP。这基本上意味着我们鼓励你以你认为可行的方式尝试使用对象,并在事情不那样时处理。

总之,唯一的问题是你的代码变得太多缩进。如果您愿意,请尝试简化一些嵌套,如lqc建议

答案 2 :(得分:8)

对于您的具体示例,您实际上不需要嵌套它们。如果try块中的表达式成功,则函数将返回,因此只有在第一次尝试失败时才会运行整个try / except块之后的任何代码。所以你可以这样做:

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass
    # execution only reaches here when try block raised AttributeError
    try:
        return self.dict[item]
    except KeyError:
        print "The object doesn't have such attribute"

嵌套它们并不坏,但我觉得保持平整会使结构更清晰:你会依次尝试一系列事情并返回第一个有效的事物。

顺便提一下,您可能想要考虑是否真的想在这里使用__getattribute__而不是__getattr__。使用__getattr__将简化操作,因为您将知道正常的属性查找过程已经失败。

答案 3 :(得分:7)

在我看来,这将是处理它的最恐怖的方式,虽然因为它使你的问题没有实际意义。请注意,这定义了__getattr__()而不是__getattribute__(),因为这样做意味着它只需要处理内部字典中保留的“特殊”属性。

def __getattr__(self, name):
    """only called when an attribute lookup in the usual places has failed"""
    try:
        return self.my_dict[name]
    except KeyError:
        raise AttributeError("some customized error message")

答案 4 :(得分:4)

在Python中,要求宽恕比获得更容易。不要让嵌套的异常处理失败。

(此外,has*几乎总是在封面下使用例外。)

答案 5 :(得分:4)

请注意 - 在这种情况下,首先触摸 public BindableMap() { GetPins(); } public async void GetPins() { BusinessRegView B = new BusinessRegView(); foreach (var i in B.BusinessRegList) { PinCollection.Add(new Pin() { Position = new Position(i.Latitude, i.Longitude), Type = PinType.Generic, Label = i.BusinessFantasyName }); } } 但也跳过了。

finally

答案 6 :(得分:2)

根据documentation,最好通过元组处理多个异常,或者像这样:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

答案 7 :(得分:2)

嵌套try / except的一个很好的简单示例如下:

import numpy as np

def divide(x, y):
    try:
        out = x/y
    except:
        try:
            out = np.inf * x / abs(x)
        except:
            out = np.nan
    finally:
        return out

现在尝试各种组合,您将获得正确的结果:

divide(15, 3)
# 5.0

divide(15, 0)
# inf

divide(-15, 0)
# -inf

divide(0, 0)
# nan

[当然,我们有numpy,所以我们不需要创建此函数]

答案 8 :(得分:1)

我喜欢避免的一件事是在处理旧的异常时引发新的异常。它使错误信息令人困惑。

例如,在我的代码中,我最初写的是

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    raise KeyError(key)

我收到了这条消息。

>>> During handling of above exception, another exception occurred.

我想要的是:

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    pass
raise KeyError(key)

它不会影响异常的处理方式。在任何一个代码块中,都会捕获KeyError。这只是获得风格点的问题。

答案 9 :(得分:0)

我不认为这是pythonic或优雅的问题。 这是一个尽可能多地防止例外的问题。 例外是为了处理您无法控制的代码或事件中可能发生的错误。 在这种情况下,您可以在检查项目是属性还是字典时完全控制,因此请避免嵌套异常并坚持第二次尝试。

答案 10 :(得分:0)

如果try-except-finally嵌套在finally块中,则最终保留“ child”的结果。我还没有找到正式的解释,但是下面的代码片段显示了Python 3.6中的这种行为。

def f2():
    try:
        a = 4
        raise SyntaxError
    except SyntaxError as se:
        print('log SE')
        raise se from None
    finally:
        try:
            raise ValueError
        except ValueError as ve:
            a = 5
            print('log VE')
            raise ve from None
        finally:
            return 6       
        return a

In [1]: f2()
log SE
log VE
Out[2]: 6