Метод .shuffle в python заканчивается бесконечным циклом, если я не переделываю перемешиваемый список - PullRequest
0 голосов
/ 09 декабря 2018

Вот код:

def share_diagonal(x0, y0, x, y):
dy = abs(x - x0)
dx = abs(y - y0)
return dy == dx


def col_clashes(list_rows_queens, coluna):
    for index in range(coluna):
    if share_diagonal(index, list_rows_queens[index], coluna, list_rows_queens[coluna]):
        return True
return False


def has_clashes(solucao):
    for coluna in range(1, len(solucao)):
        if col_clashes(solucao, coluna):
            return True
    return False


def check_repeat(a):
    for i in range(len(a)):
        for j in range(len(a)):
            if a[i] == a[j]:
                return i
    return False

def test(x):
    print(x)


def main():
    # random handle
    import random
    rng = random.Random()

    # makes a list of solutions
    solution = list(range(8))

    # initializes variables
    numbers_found = 0
    tries = 0

    #makes a list to be appended.
    unique = []


    # main loop code

    while numbers_found < 10:
        rng.shuffle(solution)                                      
        tries += 1                                                 
        if not has_clashes(solution) and solution not in unique:   
            print("Solution {0} found after {1:>} {2:>}".format(solution, tries, "tries"))
            tries = 0                                                                 
            numbers_found += 1
            unique.append(solution)                                                         
            solution = list(range(8))   # THIS LINE MADE THE CODE WORK
    print("Done. Unique solutions: {0}".format(unique))
main()

Когда у меня не было списка решений = (диапазон (8)) в главном цикле while, я получал бы бесконечный цикл, и если бы япытаясь обойти это, цифры просто не будут перемешиваться (я пытался создать функцию для добавления чисел в список = [], а затем перепроверить решения, все они оказались либо равны, либо изменились между a и,т.е. [1,2,3,4], [5,6,7,8], [1,2,3,4], [5,6,7,8] ...

Здесьобратная связь для бесконечного цикла:

/home/****/PycharmProjects/untitled/venv/bin/python /home/****/PycharmProjects/LearningToThinkLikeAComputerScientist/c14_Exercises/3.py
Solution [5, 2, 4, 7, 0, 3, 1, 6] found after 436 tries
Traceback (most recent call last):
  File "/home/****/PycharmProjects/LearningToThinkLikeAComputerScientist/c14_Exercises/3.py", line 63, in <module>
    main()
  File "/home/****/PycharmProjects/LearningToThinkLikeAComputerScientist/c14_Exercises/3.py", line 51, in main
    rng.shuffle(solution)                                      # Shuffles the list solution
  File "/usr/lib/python3.6/random.py", line 276, in shuffle
    j = randbelow(i+1)
  File "/usr/lib/python3.6/random.py", line 231, in _randbelow
    if type(random) is BuiltinMethod or type(getrandbits) is Method:
KeyboardInterrupt

Process finished with exit code 1

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

1 Ответ

0 голосов
/ 09 декабря 2018

Просматривая код, это проявление одного из наиболее распространенных gotchas вокруг изменяемых объектов и именных ссылок. Обязательное Рекомендуемое чтение здесь.
Проблема в том, что имена являются просто ссылками на фактический базовый объект python, который они представляют.Когда вы добавляете solution в список unique через unique.append(solution), unique[0] и solution оба ссылаются на один и тот же объект.

rng.shuffle(solution) перетасовывает объект, на который ссылается solution переменная на месте, таким образом solution и unique[0] оба отражают изменение, поскольку они все еще ссылаются на один и тот же объект.

Более простой пример для демонстрации.

a = [1,2,3]
b = a 
print(b)
a.append(4) #modifying the object referred to by a using one of its methods.
print(b) #[1,2,3,4]
print(a is b) #is keyword can be used to check if they are both the same object
print(id(a)) 
print(id(b)) #both id are same.

И вы можете продолжать оттуда.

a = [1, 2, 3]
b = []
b.append(a)
print(b)
a.append(4)
print(b)
import random
rng = random.Random()
rng.shuffle(a)
print(a)
print(b)

Из-за этого после первого раза, когда вы входите в блок if, и условие unique.append(solution), solution not in unique всегда возвращает возврат False, таким образом, вашцикл застревает, потому что вы больше не входите в блок if, и поэтому numbers_found не обновляется после.

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

a = [1,2,3]
b = a.copy()
print(b is a) #false
print(id(a))
print(id(b))

a = [1,2,3]
b = a[:] #slices to create a copy of the entire list.
print(b is a) #false
...