为什么这个函数被应用于一个不被称为参数的变量?

4

我在编写代码时遇到了问题。

我试图将一组包含坐标的列表(表示三维空间中一个形状可能出现的位置)转换为新列表,该列表由原始列表中的所有元素以及原始列表中的元素通过旋转[x,y,z] 坐标而得到的 [z,x,y] 和 [y,z,x] 也包含在内。

我认为这可以通过以下示例更好地说明:

假设有一个列表(表示2x2x1块的可能位置,因此称为 "two_by_two"):

two_by_two = [
    [[-1, -1, 1],  [-1, -1, 0],  [-1, 0, 0],   [-1, 0, 1]],
    [[-1, -1, 0],  [-1, -1, -1], [-1, 0, -1],  [-1, 0, 0]]
    ...
]

(省略号代表更相似的坐标列表)我试图形成完整的列表:
two_by_two_comp = [
    [[-1, -1, 1],  [-1, -1, 0],  [-1, 0, 0],   [-1, 0, 1]],
    [[-1, -1, 0],  [-1, -1, -1], [-1, 0, -1],  [-1, 0, 0]]
    ...
    [[1, -1, -1],  [0, -1, -1],  [0, -1, 0],   [1, -1, 0]],
    [[0, -1, -1],  [-1, -1, -1], [-1, -1, 0],  [0, -1, 0]]
    ...
    [[-1, 1, -1],  [-1, 0, -1],  [0, 0, -1],   [0, 1, -1]],
    [[-1, 0, -1],  [-1, -1, -1], [0, -1, -1],  [0, 0, -1]]
    ...
]

我希望你能明确理解我的意思。

我试图通过使用一个函数来实现此目标,该函数将移动two_by_two中的所有坐标:

# function to change [x, y, z] to [z, x, y]
def rotate_coordinates(parameter):
    coord_list = parameter[len(parameter) - 1]
    coordinates = coord_list[len(coord_list) - 1]

    z_coordinate = coordinates[2]
    coordinates.pop()
    coordinates.insert(0, z_coordinate)


# function to change list[x, y, z] to list[z, x, y]
def rotate_coord_list(parameter):
    coord_list = parameter[len(parameter) - 1]
    a = len(coord_list)
    while a > 0:
        coordinates = coord_list[len(coord_list) - 1]
        rotate_coordinates(parameter)
        coord_list.pop()
        coord_list.insert(0, coordinates)
        a = a - 1


# function to change list[list[x, y, z]] to list[list[z, x, y]]
def rotate_positions_list(parameter):
    b = len(parameter)
    while b > 0:
        coord_list = parameter[len(parameter) - 1]
        rotate_coord_list(parameter)
        parameter.pop()
        parameter.insert(0, coord_list)
        b = b - 1

我认为这个操作成功了,因为当我运行以下命令时:

print(two_by_two)
rotate_positions_list(two_by_two)
print(two_by_two)

输出结果:

[[[-1, -1, 1], [-1, -1, 0],  [-1, 0, 0],  [-1, 0, 1]], 
 [[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...]

[[[1, -1, -1], [0, -1, -1],  [0, -1, 0],  [1, -1, 0]], 
 [[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]]
...]

当我打算开始创建two_by_two_comp时,它会按照我的意图移动所有的坐标,但问题就出现了:

two_by_two_comp = []
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)

rotate_positions_list(two_by_two)
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)

这将返回:

[[[-1, -1, 1], [-1, -1, 0],  [-1, 0, 0],  [-1, 0, 1]], 
 [[-1, -1, 0], [-1, -1, -1], [-1, 0, -1], [-1, 0, 0]]
...]

[[[1, -1, -1], [0, -1, -1],  [0, -1, 0],  [1, -1, 0]], 
 [[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]],
... 
 [[1, -1, -1], [0, -1, -1],  [0, -1, 0],  [1, -1, 0]], 
 [[0, -1, -1], [-1, -1, -1], [-1, -1, 0], [0, -1, 0]]
...]

所以最终我得到了两个相同的“版本”two_by_two的副本,而不是移位和原始版本,并且我不知道为什么我首先打印出来的two_by_two_comp部分会受到rotate_positions_list(two_by_two)函数的影响。
如果有人能够解决我的困惑,我将非常感激。我将在下面包含完整的脚本。
谢谢, 丹
two_by_two = [
    [[-1, -1, 1],  [-1, -1, 0],  [-1, 0, 0],   [-1, 0, 1]],
    [[-1, -1, 0],  [-1, -1, -1], [-1, 0, -1],  [-1, 0, 0]],
    [[-1, 0, 0],   [-1, 0, -1],  [-1, 1, -1],  [-1, 1, 0]],
    [[-1, 0, 1],   [-1, 0, 0],   [-1, 1, 0],   [-1, 1, 1]],

    [[0, -1, 1],   [0, -1, 0],   [0, 0, 0],    [0, 0, 1]],
    [[0, -1, 0],   [0, -1, -1],  [0, 0, -1],   [0, 0, 0]],
    [[0, 0, 0],    [0, 0, -1],   [0, 1, -1],   [0, 1, 0]],
    [[0, 0, 1],    [0, 0, 0],    [0, 1, 0],    [0, 1, 1]],

    [[1, -1, 1],   [1, -1, 0],   [1, 0, 0],    [1, 0, 1]],
    [[1, -1, 0],   [1, -1, -1],  [1, 0, -1],   [1, 0, 0]],
    [[1, 0, 0],    [1, 0, -1],   [1, 1, -1],   [1, 1, 0]],
    [[1, 0, 1],    [1, 0, 0],    [1, 1, 0],    [1, 1, 1]],
]


# function to change [x, y, z] to [z, x, y]
def rotate_coordinates(parameter):
    coord_list = parameter[len(parameter) - 1]
    coordinates = coord_list[len(coord_list) - 1]

    z_coordinate = coordinates[2]
    coordinates.pop()
    coordinates.insert(0, z_coordinate)


# function to change list[x, y, z] to list[z, x, y]
def rotate_coord_list(parameter):
    coord_list = parameter[len(parameter) - 1]
    a = len(coord_list)
    while a > 0:
        coordinates = coord_list[len(coord_list) - 1]
        rotate_coordinates(parameter)
        coord_list.pop()
        coord_list.insert(0, coordinates)
        a = a - 1


# function to change list[list[x, y, z]] to list[list[z, x, y]]
def rotate_positions_list(parameter):
    b = len(parameter)
    while b > 0:
        coord_list = parameter[len(parameter) - 1]
        rotate_coord_list(parameter)
        parameter.pop()
        parameter.insert(0, coord_list)
        b = b - 1


two_by_two_comp = []
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)

rotate_positions_list(two_by_two)
two_by_two_comp.extend(two_by_two)
print(two_by_two_comp)

2
当有人回答我的问题时,我应该做什么? - RMPR
1个回答

2
您的问题在于深拷贝和浅拷贝之间的区别。根据文档
Python中的赋值语句不会复制对象,它们创建了目标和对象之间的绑定关系。对于可变或包含可变项的集合,有时需要复制一份副本,以便可以更改一个副本而不更改其他副本。
因此,有问题的行是:
two_by_two_comp.extend(two_by_two)

让我举一个例子来说明,使用两个列表ab

a = [[2, 3, 4], [1, 2, 3]]
b = []
b.extend(a)

现在假设我修改a标签内的内容:
a[0].append(3)
print(a)   #  [[2, 3, 4, 3], [1, 2, 3]]

一切都很好,但同时看看b发生了什么:

print(b)  #  [[2, 3, 4, 3], [1, 2, 3]]

它也被修改了。

为了实现你想要的效果,你需要创建 two_by_two 的深拷贝,否则你只是在引用同一内存地址。长话短说,不要这样做:

two_by_two_comp.extend(two_by_two)

您需要做的事情:

two_by_two_comp.extend(copy.deepcopy(two_by_two))

不要忘记在脚本顶部导入copy模块:
import copy 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接