2012-03-23 34 views
19

我有一个很难搞清楚这一个,它是关于可在Python 2.7抛出异常时做的错误:如果第一个元素是一个异常,为什么提出一个元组?

try: 
    raise [1, 2, 3, 4] 
except Exception as ex: 
    print ex 

这里的消息是“异常必须是老式类或BaseException衍生,没有列出” - 这部分是确定的,但是当我将其更改为元组,我越来越糊涂:

try: 
    raise (1, 2, 3, 4) 
except Exception as ex: 
    print ex 

这里的消息是‘异常必须是老式类或BaseException衍生,不是int’ - 为什么它被解释为提出一个int,而不是元组?

Futhermore:

try: 
    raise (Exception, 'a message') 
except Exception as ex: 
    print ex 

在这里,我们实际上在上升的异常(一致的行为与之前的例子,我们在那里养一个int相比) - 我简单地认为这是只为这一个替代方式:

try: 
    raise Exception, 'a message' 
except Exception as ex: 
    print ex 

但在这种情况下,“消息”被传递给异常构造函数(如记录上docs.python.org)

可有人expla在第二和第三种情况下,可能指向我在解释器中负责编码的代码?

回答

15

由于documented in the python reference,该raise声明需要长达3个表达式来创建例外被提出:

raise_stmt ::= "raise" [expression ["," expression ["," expression]]]

在Python 2中,如果第一表达式是一个元组,Python将“解包”元组递归,取第一元件,直到找到比一个元组以外的内容。此行为正在从Python 3中移除(请参阅PEP 3109。以下是合法的:

>>> raise ((Exception, 'ignored'), 'ignored'), 'something', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Exception: something 

的文档详细解释了休息,但raise语句预期的第一个值是一个异常类,第二个值被视为异常(消息)的值第三个值是回溯。如果缺失,Python将为后两个值填入None

如果第一个值是实例相反,第二个值必须是无:

>>> raise Exception('something'), 'something', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: instance exception may not have a separate value 

如果使用超过3项的元组,它会提高语法错误:

>>> raise Exception, 'something', None, None 
    File "<stdin>", line 1 
    raise Exception, 'something', None, None 
            ^
SyntaxError: invalid syntax 

在你的情况然而,你提类别,亦非一个实例,所以这是Python中被发现不正确第一;如果我使用一个字符串,它会抱怨过:

>>> raise 'not an exception', 'something', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: exceptions must be old-style classes or derived from BaseException, not str 

正确的语法是当然的:

>>> raise Exception, 'something', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Exception: something 
+0

我没有意识到递归元组展开,所以我不明白为什么其他元素被忽略--PEP是我正在寻找的缺失链接。 – dahpgjgamgan 2012-03-23 13:21:21

3

http://docs.python.org/reference/simple_stmts.html#the-raise-statement

“提高”[表达式[ “” 表达[ “” 表达]]]

如果没有表达式都存在,提高再引发的最后一个异常,在活跃当前范围...否则,raise会计算表达式以获得三个对象,并将None用作省略表达式的值。前两个对象用于确定异常的类型和值。

其实,我觉得Python做的元组拆包这里

try: 
    raise (ValueError, "foo",), "bar" 
except Exception as e: 
    print e.message # foo or bar? 

,但如果它没有,结果将是“富”,而不是“栏”。这种行为似乎并没有被记录任何地方,这里只有一张纸条,关于它的PY3被丢弃:

In Python 2, the following raise statement is legal

raise ((E1, (E2, E3)), E4), V

The interpreter will take the tuple's first element as the exception type (recursively), making the above fully equivalent to

raise E1, V

As of Python 3.0, support for raising tuples like this will be dropped. This change will bring raise statements into line with the throw() method on generator objects, which already disallows this.

http://www.python.org/dev/peps/pep-3109/#id17

+1

我看不出如何回答这个问题。谨慎解释? – 2012-03-23 09:38:50

+1

要更清楚我的评论:显然,元组被评估,以便返回第一个元素。为什么列表参数不会发生这种情况? – 2012-03-23 09:49:08

+0

似乎元组会自动解压缩(并且列表不能被解压缩)。 – kosii 2012-03-23 10:04:54

3

显然的Python还接受在raise语句,尽管第一个表达式非空的元组该文档(但是如this PEP中所述),并且如果它是元组,则它递归地使用其第一个元素作为该异常的类。让我告诉你一些代码:

>>> raise ValueError, 'sdf', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: sdf 

>>> raise (ValueError, 5), 'sdf', None 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: sdf 

尽管我在我以前的评论已经说过了,没有自动拆包,因为字符串是不传递给异常类在我的下一个例子:

>>> raise (ValueError, 'sdf', None) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError 

而且使用Python AST模块,我们可以看到,在加薪的表达没有元组默认:

>>> ast.dump(ast.parse('raise ValueError, "asd"')) 
"Module(body=[Raise(type=Name(id='ValueError', ctx=Load()), inst=Str(s='asd'), tback=None)])" 

如果我们用一个元组,这是作为类型参数传递:

>>> ast.dump(ast.parse('raise (ValueError, "asd")')) 
"Module(body=[Raise(type=Tuple(elts=[Name(id='ValueError', ctx=Load()), Str(s='asd')], ctx=Load()), inst=None, tback=None)])" 
相关问题