为什么Python引发TypeError而不是SyntaxError?

时间:2021-08-12 21:23:12

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:

但我的问题是,为什么Python引发TypeError:此处不可用的类型而不是SyntaxError?它试图散列的是什么类型?这样做:

'bar': 'baz'

is a SyntaxError, as is this:

是一个SyntaxError,如下所示:

['bar': 'baz']

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

所以我看不出哪些类型是不可用的。

2 个解决方案

#1


60  

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

在索引操作中使用冒号会生成切片对象,该对象不可清除。

#2


21  

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 :) ) :

我只是想给Ignacio的答案添加一些细节(这很棒)并且花了我一些时间来理解,对于像我这样没有得到它的人(我可能是唯一没有得到它的人,因为我没有看到有人问我不明白,但怎么知道:)):

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:

但这是我的一个愚蠢的问题,因为我忘记了python是动态的(我是多么愚蠢)所以当python编译代码时,第一次python不知道foo是字典还是列表所以它只是读取任何表达式像这个foo ['foo':'bar']作为切片,知道你可以这样做:

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模块,您将看到表达式'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   

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__:

在第一次我承认我没有想到这一点,我确实直接去了python的源代码试图理解为什么,因为列表的__getitems__不像字典的__getitem__但现在我理解为什么因为如果它切片和切片是不可取的它应该提出不可用的类型,所以这里是字典__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 :)

希望这可以帮助像我这样的人了解Ignacio的响应,对不起,如果我只是重复Ignacio的答案:)

#1


60  

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

在索引操作中使用冒号会生成切片对象,该对象不可清除。

#2


21  

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 :) ) :

我只是想给Ignacio的答案添加一些细节(这很棒)并且花了我一些时间来理解,对于像我这样没有得到它的人(我可能是唯一没有得到它的人,因为我没有看到有人问我不明白,但怎么知道:)):

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:

但这是我的一个愚蠢的问题,因为我忘记了python是动态的(我是多么愚蠢)所以当python编译代码时,第一次python不知道foo是字典还是列表所以它只是读取任何表达式像这个foo ['foo':'bar']作为切片,知道你可以这样做:

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模块,您将看到表达式'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   

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__:

在第一次我承认我没有想到这一点,我确实直接去了python的源代码试图理解为什么,因为列表的__getitems__不像字典的__getitem__但现在我理解为什么因为如果它切片和切片是不可取的它应该提出不可用的类型,所以这里是字典__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 :)

希望这可以帮助像我这样的人了解Ignacio的响应,对不起,如果我只是重复Ignacio的答案:)