【问题标题】:Why is this function being applied to a variable which is not called as a parameter?为什么将此函数应用于未作为参数调用的变量?
【发布时间】:2020-10-16 23:38:09
【问题描述】:

我在尝试编写的某些代码时遇到问题。

我正在尝试获取坐标列表(表示 3D 中形状的可能位置)并形成一个列表,该列表包含原始列表中的所有元素以及原始列表中的元素旋转,以便[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_positons_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)

【问题讨论】:

标签: python python-3.x function coordinates nested-lists


【解决方案1】:

你的问题在于深拷贝和浅拷贝的区别。根据docs

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

不要忘记在脚本顶部导入复制模块:

import copy 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 2013-12-28
    • 2018-08-15
    • 1970-01-01
    相关资源
    最近更新 更多