2010-11-11 33 views
37

純粹是出於好奇的緣故。這顯然是無效的語法:爲什麼Python會引發TypeError而不是SyntaxError?

foo = {} 
foo['bar': 'baz'] 

很明顯發生了什麼事情,開發者移動的線出來的字典中的定義,但沒有從字面解釋聲明中更改的賦值語法(並已適當嘲笑爲結果)。

但我的問題是,爲什麼Python在這裏提高TypeError: unhashable type而不是SyntaxError?它試圖散列什麼類型?只是這樣做:

'bar': 'baz' 

是一個SyntaxError,因爲是這樣的:

['bar': 'baz'] 

,所以我不能看到正在創建什麼類型,它是unhashable。

回答

59

在索引操作generates a slice object中使用冒號,這是不可散列的。

+2

我不得不承認,它並沒有發生在我身上。 +1 – delnan 2010-11-11 17:49:31

21

我只是想添加一些細節Ignacio answer(這是偉大的),並採取了一些時間來了解和喜歡我的人說沒有得到它(我可能是唯一一個沒有得到它因爲我沒有看到任何人問我不明白,但如何知道:)):

我第一次想知道什麼切片?字典索引不接受切片?

但是這是從我的一部分愚蠢的問題,因爲我忘了,蟒蛇是動態的(我是多麼愚蠢),所以當Python代碼編譯的拳頭一次蟒蛇不知道foo是一本字典或列表所以它只是這樣寫的富[「富」:「酒吧」]任意表達式作爲切片,要知道,你可以這樣做:

def f(): 
    foo = {} 
    foo['bar':'foo'] 

,並通過使用dis模塊中,你將看到的表達'bar':'foo'有已自動轉換爲切片:

dis.dis(f) 
    2   0 BUILD_MAP    0 
       3 STORE_FAST    0 (foo) 

    3   6 LOAD_FAST    0 (foo) 
       9 LOAD_CONST    1 ('bar') 
      12 LOAD_CONST    2 ('foo') 
      15 SLICE+3    <<<<<<<<<<<<<<<<<<<<<< HERE!!!!!!    
      16 POP_TOP    
      17 LOAD_CONST    0 (None) 
      20 RETURN_VALUE 

第一次我承認我沒有想到這個,我直接去了python的源代碼,試圖理解爲什麼,因爲列表的__getitems__不像__getitem__的字典,但現在我明白了爲什麼,因爲如果它切片,切片是unhashable應該提高unhashable type,所以這裏的字典__getitem__的代碼:

static PyObject * 
dict_subscript(PyDictObject *mp, register PyObject *key) 
{ 
    PyObject *v; 
    long hash; 
    PyDictEntry *ep; 
    assert(mp->ma_table != NULL); 
    if (!PyString_CheckExact(key) ||    // if check it's not a string 
     (hash = ((PyStringObject *) key)->ob_shash) == -1) { 
     hash = PyObject_Hash(key); // check if key (sliceobject) is hashable which is false 
     if (hash == -1) 
      return NULL; 
    } 
    .... 

希望這可以幫助一些人喜歡我瞭解伊格納西奧的極大反響,並抱歉,如果我只是複製伊格納西奧的答案:)

相關問題