本文介绍了Dict / Set解析顺序一致性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用可散乱对象(例如 dict 键或设置项目的容器)。因此,字典只能具有一个值为 1 1.0 True 等(注意:简化了一些 - 哈希冲突是允许的,但这些值被认为是相等的)

Containers that take hashable objects (such as dict keys or set items). As such, a dictionary can only have one key with the value 1, 1.0 or True etc. (note: simplified somewhat - hash collisions are permitted, but these values are considered equal)

我的问题是:解析顺序明确的定义是可以实现的结果对象吗?例如,OSX Python 2.7.11和3.5.1解释为 dict ,如下所示:

My question is: is the parsing order well-defined and is the resulting object predictable across implementations? For example, OSX Python 2.7.11 and 3.5.1 interprets dict like so:

>>> { True: 'a', 1: 'b', 1.0: 'c', (1+0j): 'd' }
{True: 'd'}

在这种情况下,似乎保留了第一个键和最后一个值。

In this case, it appears that the first key and the last value are preserved.

类似,在设置的情况下:

>>> { True, 1, 1.0, (1+0j) }
set([(1+0j)])

这样看来,最后一个项目被保留。

Here it appears that the last item is preserved.

但是(如评论中所述):

But (as mentioned in comments):

>>> set([True, 1, 1.0])
set([True])

文档注意到项目的顺序(例如在 dict.items )是未定义的,但是我的问题是指构建 dict set

The documentation notes that the order of items (for example in dict.items) is undefined, however my question refers to the result of constructing dict or set objects.

推荐答案

理解与列表和设置理解相反,需要两个用冒号分隔的表达式,后跟通常的for和if子句。当理解运行时,生成的键和值元素按照它们生成的顺序插入到新字典中。

A dict comprehension, in contrast to list and set comprehensions, needs two expressions separated with a colon followed by the usual "for" and "if" clauses. When the comprehension is run, the resulting key and value elements are inserted in the new dictionary in the order they are produced.

一个设置的显示产生一个新的可变集集对象,内容由表达式序列或理解指定。当提供逗号分隔的表达式列表时,其元素将从左到右进行评估,并添加到set对象中。当提供理解时,该集合是从理解结果中构建的。

调用集合构造函数有所不同或使用理解和平原文字。

There is a difference in calling the set constructor or using a comprehension and the plain literal.

def f1():
    return {x for x in [True, 1]}

def f2():
    return set([True, 1])
def f3():
    return {True, 1}
print(f1())
print(f2())
print(f3())
import dis

print("f1")
dis.dis(f1)

print("f2")

dis.dis(f2)

print("f3")
dis.dis(f3)

输出:

{True}
{True}
{1}

如何创建会影响结果:

    605           0 LOAD_CONST               1 (<code object <setcomp> at 0x7fd17dc9a270, file "/home/padraic/Dropbox/python/test.py", line 605>)
              3 LOAD_CONST               2 ('f1.<locals>.<setcomp>')
              6 MAKE_FUNCTION            0
              9 LOAD_CONST               3 (True)
             12 LOAD_CONST               4 (1)
             15 BUILD_LIST               2
             18 GET_ITER
             19 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             22 RETURN_VALUE
f2
608           0 LOAD_GLOBAL              0 (set)
              3 LOAD_CONST               1 (True)
              6 LOAD_CONST               2 (1)
              9 BUILD_LIST               2
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 RETURN_VALUE
f3
611           0 LOAD_CONST               1 (True)
              3 LOAD_CONST               2 (1)
              6 BUILD_SET                2
              9 RETURN_VALUE

Python只运行 BUILD _SET 字节码当您传递纯文字时,用逗号分隔:

Python only runs the BUILD_SET bytecode when you pass a pure literal separated by commas as per:

当提供逗号分隔的表达式列表时,其元素从左到右进行评估,并添加到设置对象中。

When a comma-separated list of expressions is supplied, its elements are evaluated from left to right and added to the set object.

理解行:

当提供理解时,该集合是从理解结果中构建的。

所以感谢Hamish的备案一个确实归结为 BUILD_SET 操作码根据Raymond Hettinger在链接中的评论的罪魁祸首是在,它不必要地向后循环,其实现如下:

So thanks to Hamish filing a bug report it does indeed come down to the BUILD_SET opcode as per Raymond Hettinger's comment in the link The culprit is the BUILD_SET opcode in Python/ceval.c which unnecessarily loops backwards, the implementation of which is below:

 TARGET(BUILD_SET) {
            PyObject *set = PySet_New(NULL);
            int err = 0;
            if (set == NULL)
                goto error;
            while (--oparg >= 0) {
                PyObject *item = POP();
                if (err == 0)
                    err = PySet_Add(set, item);
                Py_DECREF(item);
            }
            if (err != 0) {
                Py_DECREF(set);
                goto error;
            }
            PUSH(set);
            DISPATCH();
        }

这篇关于Dict / Set解析顺序一致性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 15:25