为什么 foo['bar': 'baz'] 引发 TypeError 而不是 SyntaxError?

发布于 2024-10-02 02:59:03 字数 404 浏览 6 评论 0原文

纯粹出于好奇而提出的问题。这显然是无效的语法:

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

很明显发生了什么,开发人员从字典定义中移出了一行,但没有将其从字面字典声明更改为赋值语法(因此已被适当地模拟)。

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

'bar': 'baz'

是一个SyntaxError,就像这样:

['bar': 'baz']

所以我看不到正在创建的不可散列的类型。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

躲猫猫 2024-10-09 02:59:03

在索引操作中使用冒号生成一个slice对象,不可散列。

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

时光是把杀猪刀 2024-10-09 02:59:03

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

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

但这是我的一个愚蠢的问题,因为我忘记了 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的源代码试图理解为什么,因为list的__getitems__不像字典的 __getitem__ 但现在我明白了为什么,因为如果它的切片和切片是不可散列的,它应该引发 unhashable 类型,所以这里是字典的代码 __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;
    } 
    ....

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

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

酒儿 2024-10-09 02:59:03

表达式 foo[a:b] 是 foo[slice(a, b)] 的语法糖。也就是说,您使用 slice 对象。无论 foo 是什么,都是如此。

在 Python 3.11 及更低版本中,这会引发 TypeError,因为切片对象不是 可哈希。但是,自 Python 3.12 起(2023 年发布 - 10-02),切片对象现在是可散列的1,使其用作字典键有效。

原始问题中的代码现在将引发 KeyError 而不是 TypeError

>>> foo = {}
>>> foo['bar': 'baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: slice('bar', 'baz', None)

现在也可以编写

foo = {}
foo["bar" : "baz"] = 1

生成字典 {slice('bar', 'baz',无):1}


1 前提是 startstopstep 都是可哈希的。

The expression foo[a:b] is syntactic sugar for foo[slice(a, b)]. That is, you're indexing the dictionary with a slice object. This is true regardless of what foo is.

In Python 3.11 and below, this raised a TypeError because slice objects were not hashable. However, as of Python 3.12 (released 2023-10-02), slice objects are now hashable1, making their use as dictionary keys valid.

The code in the original question will now raise a KeyError instead of a TypeError:

>>> foo = {}
>>> foo['bar': 'baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: slice('bar', 'baz', None)

It's now also possible to write

foo = {}
foo["bar" : "baz"] = 1

which produces the dictionary {slice('bar', 'baz', None): 1}.


1 Provided that start, stop, and step are all hashable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文