2010-11-11 25 views
37

Một câu hỏi hoàn toàn vì lợi ích của sự tò mò. Điều này rõ ràng là cú pháp hợp lệ:Tại sao Python nâng TypeError thay vì SyntaxError?

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

Rõ ràng những gì đã xảy ra, các nhà phát triển di chuyển một dòng ra khỏi định nghĩa từ điển nhưng không thay đổi nó từ việc khai báo từ điển đen với cú pháp chuyển nhượng (và đã được chế giễu phù hợp như một kết quả).

Nhưng câu hỏi của tôi là, tại sao Python nâng cao TypeError: unhashable type tại đây thay vì SyntaxError? Nó đang cố gắng băm gì? Chỉ cần làm điều này:

'bar': 'baz' 

là một Lỗi Cú pháp, như là thế này:

['bar': 'baz'] 

vì vậy tôi không thể nhìn thấy những loại đã được tạo ra đó là unhashable.

Trả lời

59

Sử dụng dấu hai chấm trong thao tác lập chỉ mục generates a slice object, không thể băm.

+2

Tôi phải thừa nhận, điều đó không xảy ra với tôi. +1 – delnan

21

Tôi chỉ muốn thêm một số chi tiết vào Ignacio answer (điều này thật tuyệt) và tôi mất chút thời gian để hiểu và cho những người như tôi không nhận được nó (tôi có thể là người duy nhất không hiểu bởi vì tôi không thấy ai hỏi tôi không hiểu nhưng làm sao biết được :)):

lần đầu tiên tôi tự hỏi lát nào? lập chỉ mục từ điển không chấp nhận cắt?

nhưng đây là một câu hỏi ngu ngốc từ phần của tôi vì tôi quên rằng python là động (tôi ngu ngốc thế nào) vì vậy khi python biên dịch mã, python thời gian không biết foo là từ điển hay danh sách vì thế nó chỉ cần đọc bất kỳ biểu hiện như foo này [ 'foo': 'bar'] như một lát, để biết rằng bạn chỉ có thể làm:

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

và bằng cách sử dụng dis mô-đun bạn sẽ thấy rằng sự biểu hiện 'bar':'foo' có được tự động chuyển đổi thành một lát:

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 

trong lần đầu tiên tôi thừa nhận tôi không nghĩ về điều này và tôi đã đi trực tiếp vào mã nguồn của python cố gắng hiểu tại sao, bởi vì __getitems__ của danh sách không giống như __getitem__ của một từ điển nhưng bây giờ tôi hiểu tại sao vì nếu nó một lát và lát là unhashable nó nên nâng unhashable type, vì vậy đây là mã của từ điển __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; 
    } 
    .... 

Hy vọng điều này có thể giúp một số người như tôi để hiểu được phản ứng tuyệt vời của Ignacio, và xin lỗi nếu tôi chỉ lặp lại câu trả lời của Ignacio :)

Các vấn đề liên quan