集合中的插入顺序(解析 {} 时) [英] Order of insertion in sets (when parsing {})

查看:45
本文介绍了集合中的插入顺序(解析 {} 时)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人问这里 为什么将 1True 放在 set 中时,只保留 1 .

这当然是因为1==True.但是在哪些情况下 1 被保留,在哪些情况下 True 被保留?

让我们看看:

传递一个 list 来构建 set 而不是使用 set 符号:

<预><代码>>>>设置([真,1]){真的}>>>设置([1,真]){1}

似乎合乎逻辑:set 迭代内部列表,并且不添加第二个元素,因为它等于第一个元素(注意 set([True,1]) 不能yield 1,因为set无法知道列表中的内容.它甚至可能不是列表代码> 但可迭代)

现在使用 set 表示法:

<预><代码>>>>{真,1}{1}>>>{1,真}{真的}

似乎在这种情况下,项目列表以相反的顺序处理(在 Python 2.7 和 Python 3.4 上测试).

但这能保证吗?还是只是一个实现细节?

解决方案

语言规范似乎无法保证集合字面量中元素的插入顺序.但是,Python 3.6 已更改,使其具有预期的从左到右的评估顺序.有关此更改的完整详细信息,请参阅问题,以及 commit 引入了插入顺序的变化.

<小时>

为了更详细地描述变化,构建集合文字 {True, 1} 在第一次推送后触发 BUILD_SET 操作码(oparg 等于 2)指向 True1 到虚拟机内部堆栈的指针.

在 Python 3.4 中,BUILD_SET 使用以下循环将元素插入到集合中(注意在我们的例子中 oparg 是 2):

while (--oparg >= 0) {PyObject *item = POP();如果(错误 == 0)err = PySet_Add(set, item);Py_DECREF(项目);

由于 1 是最后添加到堆栈中的,因此它首先被弹出并且是第一个插入到集合中的对象.

在较新版本的 Python(例如 3.6)中,BUILD_SET 操作码使用 PEEK 而不是 POP:

for (i = oparg; i > 0; i--) {PyObject *item = PEEK(i);如果(错误 == 0)err = PySet_Add(set, item);Py_DECREF(项目);

PEEK(i) 取栈中的第 ith 项,因此对于 {True, 1},对象 True 会先添加到集合中.

Someone asked here why when putting 1 and True in a set only 1 is kept.

This is of course because 1==True. But in which cases 1 is kept and in which cases True is kept?

Let's see:

passing a list to build the set instead of using the set notation:

>>> set([True,1])
{True}
>>> set([1,True])
{1}

seems logical: set iterates on the inner list, and doesn't add the second element because it is equal to the first element (note that set([True,1]) cannot yield 1, because set cannot know what's inside the list. It may even not be a list but an iterable)

Now using set notation:

>>> {True,1}
{1}
>>> {1,True}
{True} 

It seems that in that case, the list of items is processed in reverse order (tested on Python 2.7 and Python 3.4).

But is that guaranteed? Or just an implementation detail?

解决方案

The order the elements in the set literal will be inserted does not seem to be guaranteed by the language specification. However, Python 3.6 was changed so that it has the expected left-to-right evaluation order. For full details of this change, here is the issue, and also the commit that introduced the change in insertion order.


To describe the change in a bit more detail, building the set literal {True, 1} triggers the BUILD_SET opcode (with oparg equal to 2) after first pushing pointers to True and 1 onto the virtual machine's internal stack.

In Python 3.4, BUILD_SET uses the following loop to insert elements into the set (note that oparg is 2 in our case):

while (--oparg >= 0) {
    PyObject *item = POP();
    if (err == 0)
        err = PySet_Add(set, item);
        Py_DECREF(item);

Since 1 was added to the stack last, it is popped off first and is the first object inserted into the set.

In newer versions of Python (such as 3.6), the BUILD_SET opcode uses PEEK instead of POP:

for (i = oparg; i > 0; i--) {
    PyObject *item = PEEK(i);
    if (err == 0)
        err = PySet_Add(set, item);
        Py_DECREF(item);

PEEK(i) fetches the ith item down the stack, so for {True, 1}, the object True is added to the set first.

这篇关于集合中的插入顺序(解析 {} 时)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆