weranda
@weranda

Зачем в Python есть два способа создания копии списка?

Приветствую

Возможно существуют более двух способов создания копии списка, кроме:

b = a[:]
b = a.copy()


Но зачем нужно создавать два и более способов, когда легко можно обойтись всего одним способом?

Дополнение к вопросу:
Есть код:
a = [1 , 2, [3, 4]]

b = a[:]
c = a.copy()

print(a)
print(b)
print(c)

print()

a[1] = 0
a[2][1] = 'xx'
print(a)
print(b)
print(c)


Результат:
[1, 2, [3, 4]]
[1, 2, [3, 4]]
[1, 2, [3, 4]]

[1, 0, [3, 'xx']]
[1, 2, [3, 'xx']]
[1, 2, [3, 'xx']]


Почему так происходит – при изменении во вложенном списке с которого снята копия элементы меняются и в других списках, а отдельные элементы в скопированных списках не меняются?
  • Вопрос задан
  • 11452 просмотра
Решения вопроса 2
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Для операции среза копирование списка - это побочный эффект, а создана она для другого.

По поводу дополнения: читать про поверхностное и глубокое копирование.
Ответ написан
aRegius
@aRegius
Python Enthusiast
Приветствую, weranda.

...Почему так происходит – при изменении во вложенном списке с которого снята копия элементы меняются и в других списках, а отдельные элементы в скопированных списках не меняются?...

Потому что [:], copy(), list() создают т.н. "поверхностные" копии. Используйте copy.deepcopy() для решения подобной проблемы:
>>> a = [1 , 2, [3, 4]]
>>> import copy
>>> b = copy.deepcopy(a)
>>> a[2][1] = 156
>>> a
[1, 2, [3, 156]]
>>> b
[1, 2, [3, 4]]
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@Drozd000
Почему так происходит – при изменении во вложенном списке с которого снята копия элементы меняются и в других списках, а отдельные элементы в скопированных списках не меняются?

Как мне кажется, нашел правильный ответ на этот вопрос. Операции a[:] и a.copy() - это операции поверхностного копирования, т.е. такого копирования, при котором создается новый объект (список в данном случае) и в него записываются ссылки на все вложенные объекты.
Операция = - это операция присваивания ссылки к объекту. Не копирование.

При первой операции: a[1] = 0 - происходит присваивание ссылки к новому объекту 0. В списках b, c при этом остались ссылки на старый объект 2. Почему ссылка к новому объекту? Потому что тип int - неизменяемый, при всех операциях присваивания с неизменяемыми типами происходит присваивание ссылки к новому объекту, а не изменение старого.
То есть:
a = 5
print(id(a)) # 4489501472
a = 2
print(id(a)) # 4489501376 - объект-то новый

При второй операции a[2][1] = 'xx' изменяется объект a[2] (а это список, изменяемый, поэтому ссылка на объект не изменилась, а изменился сам список). При копировании была скопирована ссылка на этот список a[2]. Список изменился, но ссылка осталась та же во всех переменных a, b, c.

P.S. лучше поздно, чем никогда :))
Ответ написан
Denormalization
@Denormalization
Но зачем нужно создавать два и более способов, когда легко можно обойтись всего одним способом?

Програмирование - это такая штука, где одно и тоже действие можно сделать различными способами. Это касается любых языков.
Ответ написан
Комментировать
Но зачем нужно создавать два и более способов, когда легко можно обойтись всего одним способом?

.copy() добавили еще и для совместимости со словарями и множествами.

Например вместо
def foo(bar):
    if isinstance(bar, list):
        return bar[:]
    else:
        return bar.copy()

можно сделать просто
def foo(bar):
    return bar.copy()
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы