为什么处理多个异常需要一个元组而不是列表? [英] Why does handling multiple exceptions require a tuple and not a list?

查看:180
本文介绍了为什么处理多个异常需要一个元组而不是列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下示例:

  def main_list(error_type):

try:
如果error_type =='runtime':
raise RuntimeError(list error)
如果error_type =='valueerror':
raise ValueError(list error)

除了[RuntimeError,ValueError]作为e:
print str(e)

def main_tuple(error_type):

try:
如果error_type =='runtime':
raise RuntimeError(tuple error)
如果error_type =='valueerror':
raise ValueError(tuple error)

except(RuntimeError,ValueError)as e:
print str(e)


main_tuple('runtime')
main_tuple('valueerror')

main_list('runtime')
main_list('valueerror')

元组是处理多个异常类型的正确方法。使用多个异常类型的列表不会被处理。



我想知道为什么Python语法需要多个异常类型的元组。 docs 表示它使用了一个元组,所以也许只是从未被实现使用一个列表而不是一个元组。



对于我来说,在这种情况下,至少在概念上也可以使用列表。
$ b

有没有什么原因Python为什么使用元组而不是列表?

解决方案


为什么处理多个异常需要一个元组而不是一个列表?


错误处理C,在其他类型检查和异常处理之前,使用元组的特殊情况的类型检查,以便捕获多种类型的异常。



至少有一个Python核心开发人员主张使用异常处理来控制流程。添加列表作为附加类型以进行检查将对此策略起作用。



核心开发团队尚未具体解决扩展此列表以允许集合或列表虽然如果可以找到,我会很乐意参考。已经有一个关于 Python邮件列表推测相当多(另一个答案在这里引用一个反应)。



执行以下分析后,在邮件列表讨论的上下文中,我认为推理是显而易见的。我不建议建议添加其他容器。



列表失败与元组的演示



 >>> excs = TypeError,RuntimeError 
>>> lexcs = list(excs)

捕获异常的元组是有效的:

 >>>尝试:
... raise TypeError('foo')
...除了excs作为e:
... print(e)
...
foo



Python 3



的例外不起作用:

 >>>尝试:
... raise TypeError('foo')
...除了lexcs作为e:
... print(e)
...
追踪(最近的最后一次呼叫):
文件< stdin>,第2行,< module>
TypeError:foo

在处理上述异常时,发生了另一个异常:

追溯(最近最近调用):
文件 stdin>,第3行,< module>
TypeError:捕获不从BaseException继承的类不允许



Python 2.7



 >>>尝试:
... raise TypeError('foo')
...除了lexcs作为e:
... print e
...
Traceback(最近的电话最后):
文件< stdin>,第2行,< module>
TypeError:foo

这表明我们正在对特殊情况进行类型检查元组。它肯定会使代码更慢地添加另一种类型来检查,核心开发人员一直在说,这是一件好事,使用异常处理Python中的控制流程一段时间了。



源代码分析



源码的分析与上述结论一致。



语法



这不是Python的语法或解析。它会接受任何表达。因此,导致异常或元组的异常的任何表达式应该是合法的。



解组合



如果我们拆解一个在Python 3中执行此操作的功能,我们看到它将一个异常与比较操作相匹配。

 >>> def catch(例外):
... try:
... raise异常
...除了异常:
... pass
>> > import dis
>>> (d)(b)
2 0 SETUP_EXCEPT 10 10 JUMP_FORWARD 18(至31)

4>> 13 DUP_TOP
14 LOAD_FAST 0(例外)
17 COMPARE_OP 10(例外匹配)
...

这将导致我们在Python解释器中。



内部控制流程 - CPython的实现细节



CPython控制流程首先检查值是否是一个元组如果是这样,
它使用元组特定的代码遍历元组 - 寻找该值作为一个例外:

  case PyCmp_EXC_MATCH:
if(PyTuple_Check(w)){
Py_ssize_t i,length;
length = PyTuple_Size(w); (i = 0; i< length; i + = 1)
{
PyObject * exc = PyTuple_GET_ITEM(w,i);
if(!PyExceptionClass_Check(exc)){
PyErr_SetString(PyExc_TypeError,
CANNOT_CATCH_MSG);
返回NULL;
}
}
}
else {
if(!PyExceptionClass_Check(w)){
PyErr_SetString(PyExc_TypeError,
CANNOT_CATCH_MSG);
返回NULL;
}
}
res = PyErr_GivenExceptionMatches(v,w);

添加另一个类型将需要更多的内部控制流,减慢Python解释器内的控制流。 / p>

Python容器的大小



。列表也是如此,但是它们可能被分配了额外的空间,以便您可以快速添加它们(直到他们需要更大的点)。



集合占用更多空间,因为它们是哈希表。他们拥有包含对象的哈希值以及指向的指针。



结论



这是为CPython核心开发团队辩论,并为BDFL(仁者见仁者)Guido van Rossum作出决定。但是我的结论是,通过检查其他类型来减慢Python中的控制流可能会对Python模块中的控制流使用异常处理的策略起作用。



在通过上述推理之后,我不会建议他们添加这个。


Consider the following example:

def main_list(error_type):

    try:
        if error_type == 'runtime':
            raise RuntimeError("list error")
        if error_type == 'valueerror':
            raise ValueError("list error")

    except [RuntimeError, ValueError] as e:
        print str(e)

def main_tuple(error_type):

    try:
        if error_type == 'runtime':
            raise RuntimeError("tuple error")
        if error_type == 'valueerror':
            raise ValueError("tuple error")

    except (RuntimeError, ValueError) as e:
        print str(e)


main_tuple('runtime')
main_tuple('valueerror')

main_list('runtime')
main_list('valueerror')

The tuple is the correct way to handle multiple exception types. Using a list for the multiple exception types causes neither to be handled.

I am wondering why Python syntax requires a tuple for multiple exception types. The docs say that it uses a tuple, so perhaps it is just "never was implemented using a list instead of a tuple."

It seems reasonable to me that a list could also be used in this situation, conceptually at least.

Is there any reason why Python uses a tuple instead of a list for this situation?

解决方案

Why does handling multiple exceptions require a tuple and not a list?

The error handling, written in C, uses type checking for the special case of a tuple, before other type-checking and exception handling, so that multiple types of exceptions may be caught.

At least one Python core developer advocates using exception handling for control flow. Adding lists as an additional type to check would work against this strategy.

It appears that expanding this to allow for sets or lists has not been specifically addressed by the core development team, though I will gladly reference it if it can be found. There has been a discussion on the Python mailing list that speculates quite a lot (another answer here quotes one response at length).

After performing the below analysis, and in the context of the mailing list discussion, I think the reasoning is obvious. I do not suggest proposing to add other containers.

Demonstration that lists fail versus tuples

>>> excs = TypeError, RuntimeError
>>> lexcs = list(excs)

Catching the tuple of exceptions does work:

>>> try:
...   raise TypeError('foo')
... except excs as e:
...   print(e)
...
foo

Python 3

Catching the list of exceptions does not work:

>>> try:
...   raise TypeError('foo')
... except lexcs as e:
...   print(e)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: foo

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is not allowed

Python 2.7

>>> try:
...   raise TypeError('foo')
... except lexcs as e:
...   print e
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: foo

This demonstrates that we are doing type checking for the special case of a tuple. It would certainly make the code slower to add another type to check for, and the core developers have been saying that it's a good thing to use exception handling for control flow in Python for a while now.

Source Code analysis

An analysis of the source agrees with this above conclusion.

Grammar

This is not an issue for Python's grammar or parsing. It will accept any expression. Thus any expression that results in an Exception or tuple of Exceptions should be legal.

Dissassembly

If we disassemble a function that does this in Python 3, we see that it looks to match an exception with a comparison operation.

>>> def catch(exceptions):
...         try:
...             raise Exception
...         except exceptions:
...             pass
>>> import dis
>>> dis.dis(catch)
  2           0 SETUP_EXCEPT            10 (to 13)

  3           3 LOAD_GLOBAL              0 (Exception)
              6 RAISE_VARARGS            1
              9 POP_BLOCK
             10 JUMP_FORWARD            18 (to 31)

  4     >>   13 DUP_TOP
             14 LOAD_FAST                0 (exceptions)
             17 COMPARE_OP              10 (exception match)
...

This leads us inside the Python interpreter.

Internal control flow - CPython's implementation details

The CPython control flow first checks for if the value is a tuple. If so, it iterates through the tuple using tuple specific code - looking for the value to be a Exception:

case PyCmp_EXC_MATCH:
    if (PyTuple_Check(w)) {
        Py_ssize_t i, length;
        length = PyTuple_Size(w);
        for (i = 0; i < length; i += 1) {
            PyObject *exc = PyTuple_GET_ITEM(w, i);
            if (!PyExceptionClass_Check(exc)) {
                PyErr_SetString(PyExc_TypeError,
                                CANNOT_CATCH_MSG);
                return NULL;
            }
        }
    }
    else {
        if (!PyExceptionClass_Check(w)) {
            PyErr_SetString(PyExc_TypeError,
                            CANNOT_CATCH_MSG);
            return NULL;
        }
    }
    res = PyErr_GivenExceptionMatches(v, w);

Adding another type would require more internal control flow, slowing down control flow inside of the Python interpreter.

Sizes of Python Containers

Tuples are lightweight arrays of pointers. So are lists, but they may be allocated extra space so that you may quickly add to them (up to the point they need to get larger).

Sets take up much more space because they are hash tables. They have both a hash of the object they contain as well as a pointer to that which they point to.

Conclusion

This is for the CPython core development team to debate and for the BDFL (Benevolent Dictator for Life) Guido van Rossum to decide.

But my conclusion is that slowing down control flow in Python by checking for other types would work against the strategy of using exception handling for control flow in Python modules.

After reasoning through the above, I would not propose that they add this.

这篇关于为什么处理多个异常需要一个元组而不是列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆