Я работал с Python уже несколько лет и не знаю, почему он ведет себя следующим образом. Но, тем не менее, я не думаю, что когда-либо пытался работать со случайными числами именно таким образом. Пожалуйста, не стесняйтесь проверить, работает ли ваш питон (я использую 3.5) так же.
Цель . Я хочу создать список списков, в котором каждый вложенный список содержит одинаковые значения, но в разном порядке.
Какой у меня код :
import random
# Define number slots
opts = [1,2,3,4,5]
li = []
for x in range(len(opts)):
random.shuffle(opts) # Jumbles the options list
li.append(opts) # Append that list to the parent list
Итак, я объявляю список параметров, содержащих значения, которые я хочу. Затем я использую random.shuffle (), чтобы перепутать список. Затем он добавляется в основной список. Но когда я проверяю результаты, каждый вложенный список имеет один и тот же упорядоченный список чисел ...
>>> for each in li:
print(each)
[5, 4, 2, 1, 3]
[5, 4, 2, 1, 3]
[5, 4, 2, 1, 3]
[5, 4, 2, 1, 3]
[5, 4, 2, 1, 3]
>>>
Изначально у меня был более сложный код, чем выше, но, поскольку раньше я не работал с псевдослучайными числами в python, я подумал, что не до конца понимал случайный метод. Поэтому я продолжал делать код все проще и проще. Но результат был тот же. Итак, я наконец понял, что цикл for работает так, как задумано, до тех пор, пока он не завершит итерацию ...
Код с управляемыми комментариями:
import random
# Define number slots
opts = [1,2,3,4,5]
li = []
print("Now defining the list: \n")
for x in range(len(opts)):
random.shuffle(opts) # Jumble the options list
li.append(opts) # Append that list
print("li[{}] = {}".format(x,li[x])) # Outputs list associated with index
print("\nNow print each index:")
for y in range(len(li)):
print("li[{}] = {}".format(y,li[y]))
Полученные результаты:
Now defining the list:
li[0] = [3, 4, 2, 5, 1]
li[1] = [2, 1, 5, 3, 4]
li[2] = [1, 5, 2, 3, 4]
li[3] = [5, 1, 2, 4, 3]
li[4] = [2, 1, 5, 3, 4]
Now print each index:
li[0] = [2, 1, 5, 3, 4]
li[1] = [2, 1, 5, 3, 4]
li[2] = [2, 1, 5, 3, 4]
li[3] = [2, 1, 5, 3, 4]
li[4] = [2, 1, 5, 3, 4]
Итак, первый раздел вывода отражает каждый добавленный вложенный список. Второй блок вывода отражает то же самое, но после того, как цикл for завершает свою итерацию.
Я в недоумении, почему он так себя ведет. По какой-то причине каждый вложенный список изменяется на последний добавленный список, но должен произойти после или после завершения цикла for.
Есть идеи, почему?
3 ответа
Списки изменчивы. Это означает, что, хотя они имеют одну идентичность, они могут иметь много состояний . То, что вы пытаетесь сделать, это добавлять один и тот же список несколько раз, ожидая, что их текущие состояния останутся такими же. Но на самом деле, каждый раз, когда вы переставляете его, все экземпляры этого списка переставляют один и тот же путь. Изменение одного меняет их всех. Вам нужна копия этого списка, которую вы никогда не измените, поэтому она будет выглядеть замороженной:
for x in range(len(opts)):
copy = opts.copy() # make a copy
random.shuffle(copy) # shuffle only the copy
li.append(copy) # append only the copy
Вы несколько раз перетасовываете один и тот же объект списка и добавляете его в список li
каждый раз. Обратите внимание, что идентификаторы подсписков одинаковы:
>>> import random
>>> opts = [1,2,3,4,5]
>>> li = []
>>> for x in range(len(opts)):
... random.shuffle(opts)
... li.append(opts)
...
>>> li
[[1, 3, 4, 5, 2], [1, 3, 4, 5, 2], [1, 3, 4, 5, 2], [1, 3, 4, 5, 2], [1, 3, 4, 5, 2]]
>>> [id(item) for item in li]
[4392262856, 4392262856, 4392262856, 4392262856, 4392262856]
Это та же проблема, что и изменяемый аргумент по умолчанию "gotcha" а> .
Вы можете решить эту проблему с помощью копии:
>>> import random
>>> opts = [1,2,3,4,5]
>>> li = []
>>> for x in range(len(opts)):
... new_list = opts.copy()
... random.shuffle(new_list)
... li.append(new_list)
...
>>> li
[[4, 1, 2, 5, 3], [3, 5, 2, 4, 1], [3, 2, 1, 5, 4], [5, 2, 4, 1, 3], [1, 3, 5, 4, 2]]
>>> [id(item) for item in li]
[4392411016, 4392262856, 4392410952, 4392399112, 4392399048]
>>> id(opts)
4392411080
Помните, что если opts
имеет большой размер или его элементы являются большими объектами, это может привести к использованию большого количества памяти. Посмотрите на написание своего собственного генератора (возможно, перетасовывает список индексов?), Если это проблема.
В любом случае это объясняет поведение, которое вы видите.
Вы добавляете ссылки в один и тот же список снова и снова.
Вы видите результат последнего воспроизведения в случайном порядке во всех случаях.
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.