python中的.shuffle方法最终会陷入无限循环,除非我重新制作列表

时间:2018-12-09 20:06:41

标签: python list loops while-loop shuffle

代码如下:

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

当我在主while循环中没有solution = list(range(8))时,我将遇到一个无限循环,如果我尝试绕开它,数字将不会洗牌(我尝试制作一个将数字附加到列表= []上的函数,然后重新检查解决方案,所有解决方案最终都等于或在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 :(得分:0)

浏览代码,这是围绕可变对象和名称引用的最常见gotchas之一的体现。 Obligatory Recommended reading here.
问题在于名称只是对它们所代表的实际基础python对象的引用。当您通过solutionunique附加到unique.append(solution)列表中时,unique[0]solution都指向同一个对象。

rng.shuffle(solution)正对solution变量所引用的对象进行改组,因此solutionunique[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条件总是返回return 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