2010-11-11 15 views
37

Una pregunta puramente por curiosidad. Esto es obviamente una sintaxis no válida:¿Por qué Python eleva TypeError en lugar de SyntaxError?

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

Es obvio lo que sucedió, el desarrollador mueve una línea de la definición del diccionario, pero no cambió desde el literal declaración diccionario para la sintaxis de asignación (y se ha burlado de manera adecuada como un resultado).

Pero mi pregunta es, ¿por qué Python eleva TypeError: unhashable type aquí en lugar de SyntaxError? ¿Qué tipo está intentando hachís? Sólo haciendo esto:

'bar': 'baz' 

es una SyntaxError, como es esto:

['bar': 'baz'] 

así que no puedo ver qué tipo de que se está creando es unhashable.

Respuesta

59

Usando los dos puntos en una operación de indexación generates a slice object, que no es hashable.

+2

Tengo que admitir que no se me ocurrió. +1 – delnan

21

Solo quiero agregar algunos detalles al Ignacio answer (lo cual es genial) y eso me lleva algo de tiempo entender y para gente como yo que no lo entendió (puede que yo sea el único que no lo entendió) porque no vi a nadie preguntando no entendí, pero ¿cómo sabe :)):

la primera vez que me pregunto qué rebanada? indexación del diccionario no acepta rebanar?

pero esto es una pregunta estúpida de mi parte porque me olvido de que Python es dinámico (lo estúpida que soy) por lo que cuando pitón compilar el código de la pitón tiempo del puño no sé si foo es un diccionario o una lista por lo que acaba de leer cualquier expresión como esta foo [ 'foo': 'bar'] como una rebanada, para saber que sólo se puede hacer:

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

y mediante el uso dis módulo se verá que la expresión 'bar':'foo' tiene se ha convertido automáticamente a una porción:

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 

en la primera vez admito que no pensé en esto y fui directamente al código fuente de python tratando de entender por qué, porque __getitems__ de la lista no es como __getitem__ de un diccionario pero ahora entiendo por qué porque si que una rebanada y rebanada son unhashable no debe plantear unhashable type, así que aquí está el código de diccionario __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; 
    } 
    .... 

la esperanza que esto puede ayudar a algunas personas como yo entiendo la gran respuesta de Ignacio, y lo siento si acabo de duplico la respuesta de Ignacio :)

Cuestiones relacionadas