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

时间:2010-11-11 17:26:50

标签: python

一个纯粹出于好奇心的问题。这显然是无效的语法:

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

显而易见的是,开发人员从字典定义中删除了一行,但没有将它从文字字典声明更改为赋值语法(并且已经适当地模拟了结果)。

但我的问题是,为什么Python在这里而不是TypeError: unhashable type引发SyntaxError?它试图散列的是什么类型?只是这样做:

'bar': 'baz'

是一个SyntaxError,就是这样:

['bar': 'baz']

因此我无法看到正在创建的哪种类型不可用。

2 个答案:

答案 0 :(得分:63)

在索引操作generates a slice object中使用冒号,该操作不可清除。

答案 1 :(得分:21)

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

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

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

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 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;
    } 
    ....

希望这可以帮助像我一样的人理解伊格纳西奥的伟大反应,如果我只是重复伊格纳西奥的回答,我很抱歉:)