如何在Python 2.7中复制类及其列表成员而不复制引用?

时间:2011-11-16 05:07:23

标签: python class copy python-2.7

我读过有关Python类(link)的内容,这似乎是我遇到的问题。

以下是我班级和其他代码的摘录:

class s_board:

    def __init__(self):
        self.__board = [[n for n in range(1, 10)] for m in range(81)]
        self.__solved = [False for m in range(81)]

    def copy(self):
        b = s_board()
        b.__board = self.__board[:]
        b.__solved = self.__solved[:]
        return b

if __name__ == '__main__':
    A = s_board()
    B = A.copy()
    B.do_some_operation_on_lists()

当我调用B的方法对列表做某事时,A的列表似乎也会受到影响。

所以我的问题:

  • 我没有正确复制班级或名单吗?
  • 这里还有其他问题吗?
  • 如何修复它以便获得该类的新副本?

3 个答案:

答案 0 :(得分:2)

self.__board[:]创建一个新列表,其中包含对self.__board中所有相同对象的引用。由于self.__board包含列表,并且列表是可变的,因此您最终会使用部分别名数据的两个s_board实例,而更改一个会影响另一个。

正如Raymond Hettinger建议的那样,您可以使用copy.deepcopy来保证您获取对象的真实副本并且不共享任何数据。我主要说,因为我相信有一些奇怪的对象deepcopy不会起作用,但对于像列表和简单类这样的正常事情,它会正常工作。

我还有一个额外的建议。您调用b = s_board(),即为新空白板构建列表的所有工作,然后通过分配到b.__boardb.__solved将其丢弃。看起来好像做以下事情会更好:

class s_board:

    def __init__(self, board=None, solved=None):
        if board is None:
            self.__board = [[n for n in range(1, 10)] for m in range(81)]
        else:
            self.__board = copy.deepcopy(board)
        if solved is None:
            self.__solved = [False for m in range(81)]
        else:
            self.__solved = copy.deepcopy(solved)

    def copy(self):
        b = s_board(self.__board, self.__solved)
        return b

现在,如果您拨打A = s_board(),则会收到一个新的空白板,如果您拨打A.copy(),则会获得A的独特副本,而无需分配然后丢弃新的空白板。

答案 1 :(得分:0)

尝试使用deepcopy()代替copy()

copy()如果能够插入引用,deepcopy()应该复制所有成员而不使用引用。

答案 2 :(得分:0)

正在分享内部列表。这是一篇解释发生了什么的文章:http://www.python-course.eu/deep_copy.php

要修复代码,您可以使用 copy.deepcopy 确保没有共享数据:

def copy(self):
    b = s_board()
    b.__board = copy.deepcopy(self.__board)
    b.__solved = copy.deepcopy(self.__solved)
    return b