Мелкая копия в 1-D списке против 2-D списка

1

Я нашел много дискуссий, связанных с "мелкой копией" в Python, но я не могу найти свою точную проблему.

По моему мнению, создание мелкой копии по-прежнему содержит ссылки на исходные значения списка. Это справедливо в следующем случае двумерного списка.

>>> x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> y = list(x)
>>> x.append(['New value'])
>>> x
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['New value']]
>>> y
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> x[0][0] = 'A'
>>> x
[['A', 2, 3], [4, 5, 6], [7, 8, 9], ['New value']]
>>> y
[['A', 2, 3], [4, 5, 6], [7, 8, 9]]

Теперь, в одномерном списке, я не нашел этого эффекта.

>>> a = [1,2,3,4,5]
>>> b = list(a)
>>> a.append(10)
>>> a
[1, 2, 3, 4, 5, 10]
>>> b
>>> [1, 2, 3, 4, 5]
>>> a[0] = 'A'
>>> a
['A', 2, 3, 4, 5, 10]
>>> b
[1, 2, 3, 4, 5]

Кто-нибудь может прояснить, что стоит за этой разницей?

  • 1
    @mVChr: Нет, это совсем не так, как работает Python. Списки и целые обрабатываются одинаково.
  • 0
    Это даже близко к истине.
Показать ещё 2 комментария
Теги:
list
shallow-copy

3 ответа

2

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

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

Здесь вы можете увидеть эффект крупным планом. У мелкой копии b есть своя копия каждого элемента верхнего уровня; когда мы меняем a[0], скаляр, копия в b не изменяется. Затем, хотя b[2] находится в другом месте, отличном от a[2], значения указателя идентичны: они указывают на тот же список нижнего уровня. Таким образом, при изменении a[2][1] это изменение отражается в b[2][1].

>>> a = [1, 2, ['a', 'b', 'c'], 4, 5]
>>> b = list(a)
>>> a[0] = "new 1"
>>> a[2][1] = "Deeper"
>>> a
['new 1', 2, ['a', 'Deeper', 'c'], 4, 5]
>>> b
[1, 2, ['a', 'Deeper', 'c'], 4, 5]
0

Перемещение с помощью C-указателей. В списке есть много адресов, которые включают в себя список. Вы копируете только новый экземпляр всего списка, но если вы измените контент по адресу, который включен в ваш список, это повлияет на этот список. У вас 3 списка изнутри x и внутри y имеют один и тот же адрес, но x и y имеют разные адреса.

x == 0x0123  #Hexadecimal addresses
y == 0x0456
x = [0x01, 0x02, 0x03, whatever_you_want]
y = [0x01, 0x02, 0x03]
0x01 = [1, 2, 3]

Когда мы просто назначаем список вместе, если вместо y = list(x) вы написали y = x, x и y будут изменены одновременно, потому что они будут указателями на один и тот же адрес, например x = y = 0x0123.

Я не совсем уверен во всем, но как я могу это уговорить с моими фактическими знаниями в C

-1

Списки в списке являются ссылками, поэтому они используют одно и то же пространство памяти, даже если вы копируете внешний список, чтобы он этого не делал. Обратите внимание: если вы замените список во вложенном, он будет изменяться только в одной, а не в копии. Числа не являются ссылками, поэтому, когда вы копируете список, они больше не используют одно и то же пространство памяти

  • 2
    Если вы изучите адреса памяти с помощью id (который, как деталь реализации CPython, возвращает адрес памяти объекта), вы обнаружите, что этот же адрес указан для целых чисел в исходном списке или в копии.
  • 1
    Числа являются ссылками, все объекты являются ссылками, и все является объектом Python не имеет «печатных типов», которые работают иначе, чем другие объекты. Семантика всегда одинакова.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню