重新分配行为是如何出现的?

How does the re-assignment behaviour emerge?

我在这里生成超过 6 个位置的两种可能结果的所有可能排列:

paths = list(it.product([['ax','r',[],0], ['ax','l',[],0]], repeat=6))

它应该生成的是这样的:

(['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax',    
'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0])

这是包含所有结果的列表的一个元素。

我现在想根据重复模式更改 'ax' 字符串
'yp', 'p', 'xp'

为此我写了这样的东西:

for path in paths:
    axis = 1
    for axis_slice in path:
        if(axis%3 == 1):
            axis_slice[0] = 'yp'
            print(axis_slice[0])
        elif(axis%3 == 2):
            axis_slice[0] = 'p'
            print(axis_slice[0])
        elif(axis%3 == 0):
            axis_slice[0] = 'xp'
            print(axis_slice[0])
        axis+=1
    print("axis: "+str(axis))
    print(path)

然而结果是这样的:

(['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0])

然而,上面几行中的打印语句向我显示它们已正确分配,但要 'level' 返回分配('yp'、'p'、'xp') 分歧

yp
p
xp
yp
p
xp
axis: 7
(['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0], ['xp', 'r', [], 0])

这种行为是如何出现的?为什么在内循环中看不到,而在外循环中呢?我感觉这可能与评估顺序和 tuples/lists 的打包方式有关。

如何才能达到目标输出?

您的问题是 paths 中每个 path 中列表的所有成员都是同一个对象。要自己验证这一点 - 尝试:

import itertools as it
paths = list(it.product([['ax','r',[],0], ['ax','l',[],0]], repeat=6))
for path in paths:
    print([id(p) for p in path])

这将打印路径中每个列表的唯一标识符。您会看到您只有两个 ID - 您传递给 it.product.

的原始两个列表的 ID

因此,例如,如果您选择第一条路径:

(['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0], ['ax', 'r', [], 0])

它实际上是对同一个列表的 6 个引用的元组。因此,当您遍历它们时,您每次都会更改相同的列表。如果每次更改它时您使用 print(path) 而不是 axis_slice[0],您将清楚地看到发生了什么 - path 的所有 6 个成员每次都会更改。这是列表可变性和在具有可变成员的列表上使用 itertools.product 的一个特性。

Python 和 SO 老手 Ned Batchelder here 很好地涵盖了这种效果。特别是 - 查看名为 "Mutable aliasing" 的幻灯片和以下 - 尽管整篇文章确实值得一读。

如何解决这个问题将在很大程度上取决于这段代码的上下文。