Python Deepcopy和迭代返回不同的结果

Python Deepcopy和迭代返回不同的结果,python,python-3.x,Python,Python 3.x,我有一个8x8阵列,在某些位置包含对象,在其他位置包含对象。(这是一个棋盘) 我的代码运行缓慢,部分原因是使用了copy.deepcopy(x),所以我做了一些测试,发现遍历数组的速度快了32倍。当我运行代码时,它抛出了错误,所以我将迭代的结果与copy.deepcopy(x)进行了比较,结果不一样。我看不出哪里出了问题,也找不到类似的东西(我已经找过了) 功能如下: def makeCopy(array): new = [[],[],[],[],[],[],[],[]] for

我有一个8x8阵列,在某些位置包含对象,在其他位置包含对象。(这是一个棋盘)

我的代码运行缓慢,部分原因是使用了
copy.deepcopy(x)
,所以我做了一些测试,发现遍历数组的速度快了32倍。当我运行代码时,它抛出了错误,所以我将迭代的结果与
copy.deepcopy(x)
进行了比较,结果不一样。我看不出哪里出了问题,也找不到类似的东西(我已经找过了)

功能如下:

def makeCopy(array):
    new = [[],[],[],[],[],[],[],[]]
    for x in range(0,8):
        for y in range(0,8):
            new[x].append(array[x][y])
    a = copy.deepcopy(array)
    if new != a:
        print('failed')
    else:
        print('good')
    return new
当调用它时,它会打印
失败
,因此它们不相同,这会破坏我的其余代码

我传递的是这样的东西(某些工件位置可能不同):


当我尝试按原样运行代码时(使用np.ones((8,8))作为示例输入),我得到:

因为
new!=a
是:

[[假假假假]
[假假假假假假]
[假假假假假假]
[假假假假假假]
[假假假假假假]
[假假假假假假]
[假假假假假假]
[假假假假假假假]]
相反,请使用:

def生成副本(数组):
新=[]、[]、[]、[]、[]、[]、[]、[]、[]、[]、[]]
对于范围(0,8)内的x:
对于范围(0,8)内的y:
新建[x]。追加(数组[x][y])
a=复制。深度复制(数组)
if(new!=a).any():
打印('失败')
其他:
打印(“好”)
还新

这里我们使用
array.any()
来检查列表(列表)中是否有任何元素不匹配。

您的代码为我打印了“good”,我使用整数和列表的字符串列表进行了尝试,并将正确的初始列表作为参数返回给makeCopy函数。您确定要使用列表列表来测试功能吗?

您实际上没有复制矩阵中的对象

for x in range(0,8):
    for y in range(0,8):
        new[x].append(array[x][y])
使用这段代码,实际上是在两个列表之间的单个单元格中绑定同一个对象。执行此操作时,如果更改第一个列表单元格中的一个对象,它将更改另一个列表单元格中的对象。 这就是为什么它更快的原因

使用copy.deepcopy(数组)可以复制单元格以及每个单元格内的对象

Python3复制模块:

您的复制功能实际上可以很好地复制列表的结构,尽管可以通过使用列表理解来简化:
new=[[x代表行中的x]代表数组中的行]

问题是,
copy.deepcopy
的区别在于,它没有复制像
Rook('black',[0,0])
这样的实际游戏片段。 从各种评论中,我得出以下结论:

  • 这些片段没有实现
    \uuuu eq\uuuu
    ,因此
    =
    只是比较内存地址,因此您的副本被认为与
    深度复制
    不同(但可能与原始版本相同,事实上,
    深度复制
    与原始版本不同)
  • 工件包括其当前位置,例如
    [0,0]
    ,移动工件时更新/修改此位置
  • 因此,当向棋盘副本添加对同一棋子的引用时,你的极小极大算法将“移动”所有状态下的棋子,从而创建大量无效的游戏状态
以下是一些可能的解决方案,它们增加了所需重构的复杂性,但也增加了(假定的)好处:

  • 添加一个
    copy
    函数,并在创建“手动”副本时调用该方法,例如
    new=[[copy(x)for x in row]for row in array]
    在我上面的列表中;在这里,
    copy
    不是一种方法,因为在这些列表中有
    str
    和游戏块,
    copy
    必须对两者都起作用(对于
    str
    ,它可以只返回原始的)
  • 每次复制状态时,不要使用
    copy
    功能,只需在移动游戏块之前创建游戏块的副本,所有其他块可以保持不变;这样,您只需创建一个拷贝,而不是每次移动64个拷贝(不过,您仍然需要创建实际板的拷贝)
  • 完全删除你的
    Rook
    等类,只使用字符串表示法,如
    “Rb”
    表示“black Rook”,或元组
    (“Rook”,“black”)
    ,并且不冗余地包括它们的当前位置,而是在计算可能的移动时从网格本身获取它(这将是一个函数,而不是不再存在的类的方法)
用于前两种方法的
copy
功能可能看起来很简单:

def copy(piece):
    if isinstance(piece, str):
        return piece
    else:
        return type(piece)(piece.color, list(piece.position))

您还可以在循环/列表理解中的各个部分上使用
copy.deepcopy
,这可能比使用它复制整个电路板要快一点,但比定制的
copy
功能慢得多。

这只会给我
AttributeError:“bool”对象没有属性“any”
我可能不会我需要
makeCopy(array)
返回与deepcopy完全相同的值,一旦这样做了,我将删除检查并改用函数。你能提供一个输入示例吗?我想使用带形状(8,8)的numpy数组,而不是带形状(8,8)的列表造成差异编辑原始问题您是否尝试过
new=list(映射(列表,数组))
?@tobias\u k刚刚尝试过,同样的问题OK-这些自定义类是否有
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu/
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuD
for x in range(0,8):
    for y in range(0,8):
        new[x].append(array[x][y])
def copy(piece):
    if isinstance(piece, str):
        return piece
    else:
        return type(piece)(piece.color, list(piece.position))