Наборов тест на равенство, и, пока есть новые версии Python, порядок, в котором они делают это не может отличаться в зависимости в форме, которой вы передаете значения, к построению набора, как я покажу ниже.
Поскольку 0 == x
верно и0 == y
верно, но x == y
является ложным, поведение здесь действительно неопределенными, как набор предполагает, что x == y
должно быть правдой, если первые два теста тоже были верны.
Если вы обратный список, переданный set()
, то вы получите тот же результат, используя буквальным, так как порядок равенства тестирует изменения:
>>> set([y, x, 0])
set([0j, Decimal('0')])
и то же самое для реверсирования буквальным:
>>> {y, x, 0}
set([0])
что происходит, что множество буквальные загружает значения в стек, а затем значения стека добавляются в новый набор объектов в обратном порядке.
Пока 0
загружаются первого, остальные два объекта затем испытан против 0
уже в наборе. В тот момент, один из двух других объектов загружаются первым, тест равенства не удается, и вы получите добавлены два объекта:
>>> {y, 0, x}
set([Decimal('0'), 0j])
>>> {x, 0, y}
set([0j, Decimal('0')])
Это набор литералов добавлять элементы в обратном направлении является ошибка присутствует во всех версиях Python, которые поддерживают синтаксис , вплоть до Python 2.7.12 и 3.5.2. Это было недавно исправлено, см. issue 26020 (часть 2.7.13, 3.5.3 и 3.6, ни одна из которых еще не выпущена). Если вы посмотрите на 2.7.12, вы можете увидеть, что BUILD_SET
in ceval.c
считывает стек сверху вниз:
# oparg is the number of elements to take from the stack to add
for (; --oparg >= 0;) {
w = POP();
if (err == 0)
err = PySet_Add(x, w);
Py_DECREF(w);
}
в то время как байткод добавляет элементы в стек в обратном порядке (толкание 0
в стеке первого):
>>> from dis import dis
>>> dis(compile('{0, x, y}', '', 'eval'))
2 0 LOAD_CONST 1 (0)
3 LOAD_GLOBAL 0 (x)
6 LOAD_GLOBAL 1 (y)
9 BUILD_SET 3
12 RETURN_VALUE
Исправление состоит в том, чтобы читать элементы из стека в обратном порядке; Python 2.7.13 version использует PEEK()
вместо POP()
(и STACKADJ()
удалить элементы из стека впоследствии):
for (i = oparg; i > 0; i--) {
w = PEEK(i);
if (err == 0)
err = PySet_Add(x, w);
Py_DECREF(w);
}
STACKADJ(-oparg);
Равенство тестирования проблема имеет ту же причину, что и другой вопрос; класс Decimal()
имеет некоторые проблемы с равенством с complex
, который был исправлен в Python 3.2 (путем создания Decimal()
support comparisons to complex
and a few other numeric types it didn't support before).
родственные: [Dict/Set Синтаксического Order Консистенция] (https://stackoverflow.com/q/34623846/4279) – jfs