Consistency of Dict / Set Parsing Order

Containers that accept hashed objects (for example, dict keys or set elements). Thus, a dictionary can have only one key with a value of 1 , 1.0 or True , etc. (Note: several multiple hash collisions are allowed, but these values ​​are considered equal)

My question is: is parsing defined correctly and the resulting object is predictable in all implementations? For example, OSX Python 2.7.11 and 3.5.1 interprets a dict as follows:

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

In this case, it turns out that the first key and the last value are saved.

Similarly, in the case of set :

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

This shows that the last item has been saved.

But (as mentioned in the comments):

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

Now the first in the iterable is saved.

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

+18
python dictionary set python-internals
Jan 6 '16 at 0:44
source share
1 answer
  • Now fixed bug in latest python versions as described in @jsf answer

dictionary-displays

If a comma-separated sequence of key / datum pairs is specified, they are calculated from left to right to determine dictionary entries: each key object is used as a key in the dictionary to store the corresponding database. This means that you can specify the same key several times in the key / datum list, and the last dictionary value for this key will be the last.

In the understanding of dict, unlike a list and a set of concepts, two expressions are needed, separated by a colon, followed by the usual sentences "for" and "if". When understanding is performed, the resulting key elements and values ​​are inserted into the new dictionary in the order in which they are created.

set display

Displaying a set gives a new mutable given object, the contents of which are specified either by a sequence of expressions or by understanding. When a list of expressions separated by commas is provided, its elements are evaluated from left to right and added to the specified object. When understanding is provided, the set is created from elements derived from understanding.

There is a difference in calling the set constructor or using understanding and a simple 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) 

Output:

 {True} {True} {1} 

How they are created affects the result:

  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 only runs BUILD_SET when you pass a clean literal, separated by commas, as follows:

When a list of expressions separated by commas is provided, its elements are evaluated from left to right and added to the specified object.

Line for understanding:

When understanding is provided, the set is created from elements derived from understanding.

So, due to the fact that Hamish filed an error report , he really approaches the BUILD_SET code in accordance with the comment of Raymond Hettinger in the link The challenger is the BUILD_SET operation code in Python / ceval.c , which is unnecessarily looped back, the implementation of which is lower:

  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(); } 
+8
Jan 06 '16 at 1:57
source share



All Articles