Подтвердить что ты не робот

Python: копирование списка в списке

Надеюсь, что кто-то может помочь мне здесь.

Я очень новичок в Python, и я пытаюсь понять, что я делаю неправильно.

Я уже искал и выяснил, что переменные Python могут быть связаны так, что изменение одного изменяет другое, и я провел многочисленные тесты с помощью функции id(), чтобы справиться с этой концепцией. Но я, похоже, нашел исключение, я надеюсь, кто-то может объяснить...

во-первых, следующее работает, как ожидается, сделать независимую копию списка.

>>> a = [0,0]
>>> b = a[:]
>>> print a is b
False
>>> b[0]=1
>>> print a
[0,0]
>>> print b
[1,0]

Но если я немного изменил это так, чтобы a был списком в списке, он меняет...

>>> a = [[0,0],[0,0]]
>>> b = a[:]
>>> print a is b
False
>>> b[0][0]=1
>>> print a
[[1, 0], [0, 0]]
>>> print b
[[1, 0], [0, 0]]

Теперь мы видим, что любое обновление b также относится к a, но результат print a is b возвращает False? Я также проверял это на id(), все говорит, что они независимы друг от друга, но когда я обновляю одно, это относится и к другому.

Может ли кто-нибудь объяснить это?

Отмечая, что я запускаю их из http://labs.codecademy.com/#:workspace, поэтому моя первая мысль заключается в том, что это просто ошибка на их сайте, но я не знаю Не знаете?

EDIT:

СПАСИБО ВСЕМ за отличные ответы. Это было быстро! Я знаю, что это, вероятно, было задано раньше, но было трудно найти.

Поскольку все ответы верны, я буду ждать за день до маркировки. кто имеет наибольшее +1, получит отметку:)

4b9b3361

Ответ 1

b = a[:] создает мелкую копию a, поэтому изменение измененных списков в b по-прежнему влияет на те же самые списки в a.

Другими словами, a и b не указывают на один и тот же список (именно поэтому a is not b), а скорее на два разных списка, которые содержат одинаковые два списка. Вы меняете один из этих списков с помощью b[0][0] = 1, и это изменение отображается в a.

Вы упомянули, что вы играли с id(), поэтому взгляните на это:

>>> a = [[0,0],[0,0]]
>>> b = a[:]
>>> id(a)
2917280                    # <----+
>>> id(b)                  #      |----- different!
2771584                    # <----+
>>> id(a[0]), id(a[1])
(2917320, 2917360)         # <----+
>>> id(b[0]), id(b[1])     #      |----- same!
(2917320, 2917360)         # <----+

Ответ 2

Вам нужно сделать глубокую копию вашего списка. a[:] делает только мелкую копию - см. документы

Вы можете использовать функцию copy.deepcopy:

>>> import copy
>>> a = [[0,0],[0,0]]
>>> b = copy.deepcopy(a)
>>> b
[[0, 0], [0, 0]]
>>> b[0][0]=1
>>> a
[[0, 0], [0, 0]]

Ответ 3

Я считаю, что самый простой способ получить то, что происходит, это использовать визуальное представление (идея этого представления не моя, хотя мне она нравится).

Прежде всего, вам нужно понять, что в python есть только ссылки на объекты. Сами объекты живут отдельно друг от друга. Например, список [0, 1] - это список-объект, содержащий ссылки на объект 0 и объект 1. Ссылка - это своего рода ссылка. Это отличается от переменных на других языках, поскольку переменные обычно являются ячейками памяти, в которые вы помещаете вещи. В python "переменная", то есть идентификатор, является просто "именем" (= ссылкой) для объекта.

Чтобы понять это, давайте посмотрим на отношения между объектами с метафорой: Скажем, объекты - это тяжелые скалы в море, которые связаны веревками и крючками (¿). На поверхности моря живут идентификаторы, которые относятся к объектам. Идентификаторы - это буи, которые препятствуют погружениям объектов в глубины (где, скажем, морские монстры (они же Мусорщик) уничтожают их).

Например, мы можем представить эту ситуацию:

a = [0, 1]

Со следующей диаграммой:

         ___
        (   )
~~~~~~~~( a )~~~~~~~~
        (___)
 o        ¿      o
          |       O
          |    o
          |
          |
   +------+-------+
   | [  ¿   , ¿ ] |
   +----|-----|---+
        |     |
        |     |
   o    |     |
 O      |     |
        |     |
      +-+-+ +-+-+
      | 0 | | 1 |
      +---+ +---+

 o                 O  o
    )
   (  )             o
  ) )(  )        ( (
 ( (  )( (      ( ) )

Как вы можете видеть, идентификатор a ссылается, т.е. связан с канатом, на объект списка. Объект list имеет два слота, каждый из которых содержит ссылку, связанную с объектами 0 и 1.

Теперь, если бы мы сделали:

b = a

Идентификатор b будет ссылаться на тот же объект a:

            ___                 ___
           (   )               (   )
~~~~~~~~~~~( a )~~~~~~~~~~~~~~~( b )~~~~~~~~~~~~~~~~
           (___)               (___)
             ¿                   ¿
              \                 /
    o          \               /             o
  o             \             /            o
                -------+-------
     O         |  [ ¿  ,  ¿ ]  |              O
                ----|-----|----
                    |     |
                  +-+-+ +-+-+
         o        | 0 | | 1 |
                  +---+ +---+              o
    O
       o                              O
                                         o


               )
            ) (                    ) (
         ( (   )(               ( (   )
        ( ) ) (  ) (           ( ) ) (  )

Если вместо этого сделайте небольшую копию a, используя:

b = a[:]

Создается новый список, а его элементы - копии ссылок на объекты, на которые ссылается a, т.е. вы сделали копии веревок, но они указывают на те же элементы:

               ___                 ___
               (   )               (   )
    ~~~~~~~~~~~( a )~~~~~~~~~~~~~~~( b )~~~~~~~~~~~~~~~~
               (___)               (___)
    O            ¿                   ¿               o
                 |                   |
       o         |                   |
                 |                   |
          -------+------       ------+-------
         |  [ ¿  , ¿ ]  |     |  [ ¿ ,  ¿  ] |
          ----|----|----       ----|----|----
              |    |               |    |
               \    \             /    /
                \    \           /    /
                 \    \         /    /            o
    o             \    \       /    /           o
                   \    \     /    /               o
       o            \    \   /    /
                     \    \ /    /             o
   O                  \    X    /
                       \  / \  /
                        \/   \/
                        |     |
                        |     |
                        |     |
                      +-+-+ +-+-+
                      | 0 | | 1 |
                      +---+ +---+



                 )
           (    (                  )      (
     )(     )    )  )           ( (   )    )  )
    (  )   (  ) (  (  (       (  ) ) (  ) (  (  (

Поскольку целые числа неизменны, нет никакой разницы между копиями или одинаковыми идентичными объектами, но при замене целых чисел на list s, которые изменяются, вы в конечном итоге изменяете ссылки на один и тот же объект, следовательно, поведение, которое вы видите.

Визуально, код:

a = [[0, 1], [0, 1]]
b = a[:]

Результаты в:

                ___                 ___
               (   )               (   )
    ~~~~~~~~~~~( a )~~~~~~~~~~~~~~~( b )~~~~~~~~~~~~~~~~
               (___)               (___)
    O            ¿                   ¿               o
                 |                   |
       o         |                   |
                 |                   |
          -------+------       ------+-------
         |  [ ¿  , ¿ ]  |     |  [ ¿ ,  ¿  ] |
          ----|----|----       ----|----|----
              |     \             /     |
              |      \           /      |
              |       \         /       |
              |        \       /        |
              |         \     /         |
              |          \   /          |
              |           \ /           |
              |            X            |
              |           / \           |
              |          /   \          |
              |         /     \         |
              |        /       \        |
              |       /         \       |
              |      /           \      |
              |     |             \     |
              |     |              |    |
         +----+-----+----+   +-----+----+----+
         | [  ¿  ,  ¿  ] |   | [  ¿  ,  ¿  ] |
         +----|-----|----+   +----|-----|----+
               \     \           /     /
                \     \         /     /
                 \     \       /     /
                  \     \     /     /
                   \     \   /     /
                    \     | /     /
                     |    |/     /
                     |    X     /
                     |   / |   /
                     |  /  |  /
                     \ /   \ /
                      Y     Y
                      |     |
                    +-+-+ +-+-+
                    | 0 | | 1 |
                    +---+ +---+


               )
         (    (                  )      (
   )(     )    )  )           ( (   )    )  )
  (  )   (  ) (  (  (       (  ) ) (  ) (  (  (

Обратите внимание, что список b относится к тем же подспискам a. (подробности реализации: компилятор CPython bytecode будет оптимизировать литералы, так что те же объекты 0 и 1 используются в обоих подсписок. Также существует некоторое кэширование для небольших целых чисел, но это не важно. подписи не имеют всех общих элементов).

Глубокая копия - это копия, которая позволяет избежать совместного использования одинаковых объектов.

Например, после выполнения:

import copy
a = [[0, 1], [0, 1]]
b = copy.deepcopy(a)

Ситуация такова:

                ___                                              ___
               (   )                                            (   )
    ~~~~~~~~~~~( a )~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~( b )~~~~~~~~~~~~~~~~
               (___)                                            (___)
    O            ¿                                                ¿               o
                 |                                                |
       o         |                                                |
                 |                                                |
          -------+------                                   -------+------
         |  [ ¿  , ¿ ]  |                                 |  [ ¿  , ¿ ]  |
          ----|----|----                                   ----|----|----
              |     \                                          |     \
              |      \                                         |      \
              |       \                                        |       \
              |        \                                       |        \
              |         \                                      |         \
              |          \                                     |          \
              |           \                                    |           \
              |            \                                   |            \
              |             \                                  |             \
              |              \                                 |              \
              |               \                                |               \
              |                \                               |                \
         +----+----------+   +--+------------+            +----+----------+   +--+------------+
         | [  ¿  ,  ¿  ] |   | [  ¿  ,  ¿  ] |            | [  ¿  ,  ¿  ] |   | [  ¿  ,  ¿  ] |
         +----|-----|----+   +----|-----|----+            +----|-----|----+   +----|-----|----+
               \     \           /     /                        \     \           /     /
                \     \         /     /                          \     \         /     /
                 \     \       /     /                            \     \       /     /
                  \     \     /     /                              \     \     /     /
                   \     \   /     /                                \     \   /     /
                    \     | /     /                                  \     | /     /
                     |    |/     /                                    |    |/     /
                     |    X     /                                     |    X     /
                     |   / |   /                                      |   / |   /
                     |  /  |  /                                       |  /  |  /
                     \ /   \ /                                        \ /   \ /
                      Y     Y                                          Y     Y
                      |     |                                          |     |
                    +-+-+ +-+-+                                      +-+-+ +-+-+
                    | 0 | | 1 |                                      | 0 | | 1 |
                    +---+ +---+                                      +---+ +---+






               )                                               )
         (    (                  )      (                (    (                  )      (
   )(     )    )  )           ( (   )    )  )      )(     )    )  )           ( (   )    )  )
  (  )   (  ) (  (  (       (  ) ) (  ) (  (  (   (  )   (  ) (  (  (       (  ) ) (  ) (  (  (

(На самом деле кажется, что copy.deepcopy достаточно умен, чтобы избежать копирования неизменяемых встроенных объектов, таких как int, long, tuple неизменяемых объектов и т.д. поэтому все подсписцы имеют одни и те же объекты 0 и 1)


Обратите внимание, что эти диаграммы также могут помочь вам понять, как работает подсчет ссылок. Каждая веревка является ссылкой, и пока объект не имеет цепочку ссылок, которая поднимается до буя (то есть идентификатор), он остается живым. Когда больше нет веревок, чтобы связать объект с поверхностными буями, тогда объекты погружаются и уничтожаются сборщиком мусора.

Ответ 4

a - список списков. Когда вы делаете b=a[:], вы создаете новый список, но копируете элементы. Таким образом, b - это другой список, но элементы (подписи) одинаковы.

Ответ 5

В обоих случаях создается независимый список. Таким образом, a is b всегда false.

В первом случае вы помещаете некоторые другие значения в один из списков.

Во втором случае ваши списки содержат одинаковые значения.

Как будто вы пишете

l = []
a = [l, l]
b = [l, l]

a is not b, и тем не менее они содержат одни и те же данные.

Если вы измените l сейчас, это изменение будет видно через все a[0], a[1], b[0] и b[1].

Ответ 6

Хотя a is b возвращает False, a[0] is b[0] возвращает True. Поэтому, когда вы меняете b[0], вы обязательно меняете a[0]

>>> a = [[0,0],[0,0]]
>>> b = a[:]

>>> # a[0] is b[0] 
>>> print a[0] is b[0]
True

>>> a.append('more stuff')
>>> print a
[[0, 0], [0, 0], 'more stuff']
>>> print b
[[0, 0], [0, 0]]

Ответ 7

Есть альтернатива дорогостоящей дорогостоящей глубине, когда вы имеете дело со списками внутри списков

origvector=[]
    for ind in range(0, len(testvector)):
        origvector.append(testvector[ind][:])

В этом примере "testvector" представляет собой матрицу из n векторов, каждый элемент содержит список из трех элементов. Вот так:

{0,1,2}{10,20,30}
{3,4,5}{40,50,60}
{6,7,8}{70,80,90}