Why does Python raise TypeError rather than SyntaxError?

Question:

A question purely for curiosity’s sake. This is obviously invalid syntax:

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

It’s obvious what happened, the developer moved a line out of the dictionary definition but didn’t change it from the literal dictionary declaration to the assignment syntax (and has been suitably mocked as a result).

But my question is, why does Python raise TypeError: unhashable type here rather than SyntaxError? What type is it attempting to hash? Just doing this:

'bar': 'baz'

is a SyntaxError, as is this:

['bar': 'baz']

so I can’t see what type is being created that is unhashable.

Asked By: Daniel Roseman

||

Answers:

Using the colon in an indexing operation generates a slice object, which is not hashable.

I just want to add some detail to Ignacio answer (which is great) and that take me some time to understand and for people like me that didn’t get it (i may be the only one that didn’t get it because i didn’t see anyone asking i didn’t understand but how knows 🙂 ) :

the first time i wonder what slice ? dictionary indexing don’t accept slicing ?

but this is a stupid question from my part because i forget that python is dynamic (how stupid i’m ) so when python compile the code the fist time python don’t know if foo is a dictionary or a list so it just read any expression like this foo[‘foo’:’bar’] as a slice , to know that you can just do:

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

and by using dis module you will see that the expression 'bar':'foo' has been automatically convert to a slice:

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   

in the first time i admit i didn’t think about this and i did go directly to the source code of python trying to understand why, because the __getitems__ of list is not like __getitem__ of a dictionary but now i understand why because if it a slice and slice are unhashable it should raise unhashable type, so here is the code of dictionary __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;
    } 
    ....

Hope this can help some people like me to understand the great response of Ignacio, and sorry if i just duplicate the answer of Ignacio 🙂

Answered By: mouad
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.