Как мне скопировать класс и его список членов в Python 2.7, а не скопировать ссылки? - PullRequest
1 голос
/ 16 ноября 2011

Я читал это о классах Python ( ссылка ), и, похоже, у меня возникла проблема.

Вот выдержка из моего класса и другой код:

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

Когда я вызываю метод Б, который что-то делает со списком, списки А, похоже, также затрагиваются.

Поэтому мои вопросы:

  • Не копирую ли якласс или списки правильно?
  • Есть ли здесь еще одна проблема?
  • Как мне исправить это, чтобы я получил новую копию класса?

Ответы [ 3 ]

2 голосов
/ 16 ноября 2011

self.__board[:] создает новый список, содержащий ссылки на все те же объекты, которые были в self.__board. Поскольку self.__board содержит списки, а списки являются изменяемыми, в итоге вы получаете два экземпляра s_board с частично псевдонимами данных, и изменение одного влияет на другой.

Как предположил Рэймонд Хеттингер, вы можете использовать copy.deepcopy, чтобы (в основном) гарантировать, что вы берете истинную копию объекта и не передаете какие-либо данные. В основном я говорю, поскольку считаю, что есть некоторые странные объекты, над которыми deepcopy не будет работать, но для обычных вещей, таких как списки и простые классы, он будет работать нормально.

У меня есть дополнительное предложение. Вы вызываете b = s_board(), что требует усилий для создания списков для новой пустой доски, а затем вы выбрасываете их, назначая b.__board и b.__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, без необходимости выделять и затем сбрасывать новую пустую доску.

0 голосов
/ 16 ноября 2011

Внутренние списки являются общими. Вот статья, которая объясняет, что происходит: 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
0 голосов
/ 16 ноября 2011

попробуйте использовать deepcopy() вместо copy()

copy() вставляет ссылки, если это возможно, deepcopy() должен скопировать все элементы без использования ссылок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...