Подтвердить что ты не робот

Согласованность порядка Dict/Set Parsing

Контейнеры, которые принимают хешируемые объекты (например, dict ключи или set элементы). Таким образом, словарь может иметь только один ключ со значением 1, 1.0 или True и т.д. (Примечание: разрешены несколько несколько хэш-коллизий, но эти значения считаются равными)

Мой вопрос: правильно ли определен синтаксический анализ и результирующий объект предсказуем во всех реализациях? Например, OSX Python 2.7.11 и 3.5.1 интерпретирует dict следующим образом:

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

В этом случае оказывается, что первый ключ и последнее значение сохраняются.

Аналогично, в случае set:

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

Здесь показано, что последний элемент сохранен.

Но (как упоминалось в комментариях):

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

Теперь первый в итерабеле сохраняется.

В документации отмечается, что порядок элементов (например, в dict.items) равен undefined, однако мой вопрос относится к результату построения объектов dict или set.

4b9b3361

Ответ 1

  • Теперь исправлена ​​ошибка в последних версиях python, как описано в @jsf answer

dictionary-displays

Если задана разделенная запятыми последовательность пар ключ /datum, они вычисляются слева направо для определения записей словаря: каждый ключевой объект используется в качестве ключа в словаре для хранения соответствующей базы данных. Это означает, что вы можете указать один и тот же ключ несколько раз в списке key/datum, и последнее значение словаря для этого ключа будет последним.

В понимании dict, в отличие от списка и набора понятий, нужны два выражения, разделенные двоеточием, за которыми следуют обычные предложения "для" и "если". Когда понимание выполняется, результирующие элементы ключа и значения вставляются в новый словарь в том порядке, в котором они создаются.

установить отображение

Отображение набора дает новый изменяемый заданный объект, содержимое которого задается либо последовательностью выражений, либо пониманием. Когда предоставляется список выражений, разделенных запятыми, его элементы оцениваются слева направо и добавляются к заданному объекту. Когда предоставляется понимание, набор создается из элементов, полученных в результате понимания.

Существует разница в вызове конструктора set или использовании понимания и простого литерала.

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, когда вы передаете чистый литерал, разделенный запятыми, следующим образом:

Когда предоставляется список выражений, разделенных запятыми, его элементы оцениваются слева направо и добавляются к заданному объекту.

Линия для понимания:

Когда предоставляется понимание, набор создается из элементов, полученных в результате понимания.

Итак, благодаря тому, что Хэмиш подал отчет об ошибке , он действительно подходит к коду BUILD_SET в соответствии с комментарием Раймонда Хеттингера в ссылке Претендентом является код операции BUILD_SET в Python/ceval.c, который излишне петли назад, реализация которого ниже:

 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();
        }