Установить порядок итераций варьируется от запуска к запуску - PullRequest
20 голосов
/ 03 октября 2010

Почему порядок итераций набора Python (с одним и тем же содержимым) варьируется от прогона к прогону, и каковы мои варианты сделать его согласованным от прогона к прогону?

Я понимаю, что порядок итерациидля набора Python является произвольным.Если я помещу «a», «b» и «c» в набор, а затем переберу их, они могут вернуться в любом порядке.

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

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

Лучшее решение, которое я нашел, это:

  1. Копироватьнабор к списку.
  2. Применение произвольной сортировки к списку.
  3. Итерация списка вместо набора.

Есть ли более простое решение?

Примечание. Я нашел похожие вопросы в StackOverlow, но ни один из них не касался этой конкретной проблемы получения одних и тех же результатов от запуска к запуску.

Ответы [ 7 ]

14 голосов
/ 03 октября 2010

Используйте оператор symbric_difference (^) на ваших двух наборах, чтобы увидеть, есть ли различия:

In [1]: s1 = set([5,7,8,2,1,9,0])
In [2]: s2 = set([9,0,5,1,8,2,7])
In [3]: s1
Out[3]: set([0, 1, 2, 5, 7, 8, 9])
In [4]: s2
Out[4]: set([0, 1, 2, 5, 7, 8, 9])
In [5]: s1 ^ s2
Out[5]: set()
14 голосов
/ 03 октября 2010

То, что вы хотите, не возможно. Произвольный означает произвольный.

Мое решение будет таким же, как и у вас, вы должны отсортировать набор, если хотите иметь возможность сравнить его с другим.

10 голосов
/ 11 сентября 2015

Причина, по которой установленный порядок итераций изменяется от прогона к прогоне, заключается в том, что Python по умолчанию использует рандомизацию начального числа хэша.(См. Опцию команды -R.) Таким образом, итерация набора не только произвольна (из-за хеширования), но и недетерминирована (из-за случайного начального числа).

Вы можете переопределитьслучайное начальное число с фиксированным значением путем установки переменной среды PYTHONHASHSEED для интерпретатора.Использование одного и того же начального числа от запуска к запуску означает, что итерация набора все еще произвольна, но теперь она является детерминированной, что и было желаемым свойством.

Рандомизация начального числа хэша является мерой безопасности, затрудняющей злоумышленнику подавать входные данныеэто вызовет патологическое поведение (например, путем создания многочисленных коллизий хешей).Для модульного тестирования это не проблема, поэтому разумно переопределять начальное число хеша при выполнении тестов.

5 голосов
/ 03 октября 2010

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

Как уже говорили другие: если вы заботитесь о порядкеустановить, вы должны создать отсортированный список из него.

2 голосов
/ 23 октября 2011

Ваш вопрос преобразован в два вопроса: А) как сравнить «результат двух прогонов» в вашем конкретном случае;Б) каково определение порядка итераций в множестве.Может быть, вы должны выделить их и опубликовать B) как новый вопрос, если это уместно.Я отвечу А.

ИМХО, использование отсортированного списка в вашем случае не очень чистое решение.Вы должны решить, будете ли вы заботиться о порядке итерации раз и навсегда и использовать соответствующую структуру.

Либо 1) вы хотите сравнить два набора, чтобы увидеть, имеют ли они одинаковое содержание, независимо от порядка.Тогда простой оператор == на множествах кажется подходящим.Смотрите наборы python2 , наборы python3 .

или 2) вы хотите проверить, были ли элементы вставлены в том же порядке.Но это кажется разумным только в том случае, если порядок вставки так или иначе имеет значение для пользователей вашей библиотеки, и в этом случае использование типа set было бы, вероятно, неуместным для начала.Другими словами, неясно, что именно вы подразумеваете под «сравнением результатов двух прогонов» и почему вы хотите это сделать.

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

1 голос
/ 01 декабря 2016

Вы также можете установить ожидаемый результат как набор.И проверяет, равны ли эти два набора, используя ==.

0 голосов
/ 03 октября 2010

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

...