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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17015230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:13:44  来源:igfitidea点击:

Are nested try/except blocks in python a good programming practice?

python

提问by Michal

I'm writing my own container, which needs to give access to a dictionary inside by attribute calls. The typical use of the container would be like this:

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

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

I know that it might be stupid to write something like this, but that's the functionality I need to provide. I was thinking about implementing this in a following way:

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

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"

I'm not sure whether nested try/except blocks are a good practice so another way would be to use hasattr()and has_key():

我不确定嵌套的 try/except 块是否是一个好习惯,所以另一种方法是使用hasattr()and 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")

Or to use one of them and one try catch block like this:

或者使用其中之一和一个 try 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")

Which option is most pythonic and elegant?

哪个选项最pythonic和优雅?

采纳答案by lqc

Your first example is perfectly fine. Even the official Python docs recommend this style known as EAFP.

你的第一个例子非常好。甚至官方 Python 文档也推荐这种称为EAFP 的样式。

Personally, I prefer to avoid nesting when it's not necessary:

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

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. has_key()has been deprecated for a long time in Python 2. Use item in self.dictinstead.

附注。has_key()在 Python 2 中已经弃用了很长时间。请item in self.dict改用。

回答by Ignacio Vazquez-Abrams

In Python it is easier to ask for forgiveness than permission. Don't sweat the nested exception handling.

在 Python 中,请求宽恕比请求许可更容易。不要担心嵌套的异常处理。

(Besides, has*almost always uses exceptions under the cover anyways.)

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

回答by BrenBarn

For your specific example, you don't actually need to nest them. If the expression in the tryblock succeeds, the function will return, so any code after the whole try/except block will only be run if the first attempt fails. So you can just do:

对于您的具体示例,您实际上并不需要嵌套它们。如果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"

Nesting them isn't bad, but I feel like leaving it flat makes the structure more clear: you're sequentially trying a series of things and returning the first one that works.

嵌套它们也不错,但我觉得让它保持平坦会使结构更加清晰:您正在依次尝试一系列事情并返回第一个有效的事情。

Incidentally, you might want to think about whether you really want to use __getattribute__instead of __getattr__here. Using __getattr__will simplify things because you'll know that the normal attribute lookup process has already failed.

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

回答by Bruno Penteado

While in Java its indeed a bad practice to use Exceptions for flow control (mainly because exceptions force the jvm to gather resources (more here)), in Python you have 2 important principles: Duck Typingand EAFP. This basically means that you are encouraged to try using an object the way you think it would work, and handle when things are not like that.

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

In summary the only problem would be your code getting too much indented. If you feel like it, try to simplify some of the nestings like lqc suggested

总之,唯一的问题是您的代码缩进太多。如果你喜欢,试着简化一些像 lqc 建议的嵌套

回答by owobeid

I don't think it's a matter of being pythonic or elegant. It's a matter of preventing exceptions as much as you can. Exceptions are meant to handle errors that might occur in code or events you have no control over. In this case you have full control when checking if an item is an attribute or in a dictionary, so avoid nested exceptions and stick with your second attempt.

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

回答by martineau

In my opinion this would be the most Pythonic way to handle it, although and because it makes your question moot. Note that this defines__getattr__()instead of__getattribute__()because doing so means it only has to deal with the "special" attributes being keep in the internal dictionary.

在我看来,这将是处理它的最 Pythonic 的方式,尽管并且因为它使您的问题没有实际意义。请注意,这是定义__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")

回答by Steve Zelaznik

One thing I like to avoid is raising a new exception while handling an old one. It makes the error messages confusing to read.

我喜欢避免的一件事是在处理旧异常时引发新异常。它使错误消息难以阅读。

For example, in my code, I originally wrote

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

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

And I got this message.

我收到了这条消息。

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

What I wanted was this:

我想要的是这样的:

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

It doesn't affect how exceptions are handled. In either block of code, a KeyError would have been caught. This is merely an issue of getting style points.

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

回答by Blairg23

According to the documentation, it is better to handle multiple exceptions through tuples or like this:

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

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

回答by S?awomir Lenart

Just be careful - in this case first finallyis touched BUT skipped too.

请小心 - 在这种情况下,第一个finally被触及但也被跳过。

def a(z):
    try:
        100/z
    except ZeroDivisionError:
        try:
            print('x')
        finally:
            return 42
    finally:
        return 1


In [1]: a(0)
x
Out[1]: 1

回答by Guanghua Shu

If try-except-finally is nested inside finally block, the result from "child" finally is preserved. I have not found official expaination yet, but the following code snippet shows this behavior in Python 3.6.

如果 try-except-finally 嵌套在 finally 块中,则保留“child” finally 的结果。我还没有找到官方解释,但以下代码片段显示了 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