2012-03-23 35 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)])" 
相關問題