it-swarm.com.ru

Как клонировать или скопировать список?

Какие есть варианты для клонирования или копирования списка в Python?

При использовании new_list = my_list любые изменения new_list изменяют my_list каждый раз. Почему это?

2122
aF.

С new_list = my_list у вас фактически нет двух списков. Назначение просто копирует ссылку на список, а не на фактический список, поэтому и new_list, и my_list ссылаются на один и тот же список после назначения.

Чтобы фактически скопировать список, у вас есть различные возможности:

  • Вы можете использовать встроенный метод list.copy() (доступен с Python 3.3):

    new_list = old_list.copy()
    
  • Вы можете нарезать это:

    new_list = old_list[:]
    

    Алекса Мартелли мнение (по крайней мере в 2007 году ) о том, что это странный синтаксис и использовать его не имеет смысла Когда-либо. ;) (По его мнению, следующий более читабелен).

  • Вы можете использовать встроенную функцию list() :

    new_list = list(old_list)
    
  • Вы можете использовать generic copy.copy() :

    import copy
    new_list = copy.copy(old_list)
    

    Это немного медленнее, чем list(), потому что он должен сначала выяснить тип данных old_list.

  • Если список содержит объекты, и вы хотите скопировать их, используйте generic copy.deepcopy() :

    import copy
    new_list = copy.deepcopy(old_list)
    

    Очевидно, самый медленный и самый требующий памяти метод, но иногда неизбежный.

Пример:

import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance 
a.append('baz')
foo.val = 5

print('original: %r\n list.copy(): %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r'
      % (a, b, c, d, e, f))

Результат:

original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]
2841
Felix Kling

Феликс уже дал отличный ответ, но я подумал, что я сделаю сравнение скорости различных методов:

  1. 10,59 с (105,9us/itn) - copy.deepcopy(old_list)
  2. 10,16 с (101,6us/itn) - чистый метод python Copy(), копирующий классы с глубокой копией
  3. 1.488 сек (14.88us/itn) - чистый метод python Copy() не копирует классы (только dicts/lists/tuples)
  4. 0,325 с (3,25us/itn) - for item in old_list: new_list.append(item)
  5. 0,217 с (2,17us/itn) - [i for i in old_list] (a понимание списка )
  6. 0,186 с (1,86US/ITN) - copy.copy(old_list)
  7. 0,075 с (0,75us/itn) - list(old_list)
  8. 0,053 с (0,53us/itn) - new_list = []; new_list.extend(old_list)
  9. 0,039 с (0,39us/itn) - old_list[:] ( нарезка списка )

Так что самым быстрым является нарезка списка. Но имейте в виду, что copy.copy(), list[:] и list(list), в отличие от copy.deepcopy() и версии python, не копируют никакие списки, словари и экземпляры классов в списке, поэтому, если оригиналы изменятся, они будут изменены в скопированном списке тоже и наоборот.

(Вот сценарий, если кто-то заинтересован или хочет поднять какие-либо вопросы :)

from copy import deepcopy

class old_class:
    def __init__(self):
        self.blah = 'blah'

class new_class(object):
    def __init__(self):
        self.blah = 'blah'

dignore = {str: None, unicode: None, int: None, type(None): None}

def Copy(obj, use_deepcopy=True):
    t = type(obj)

    if t in (list, Tuple):
        if t == Tuple:
            # Convert to a list if a Tuple to 
            # allow assigning to when copying
            is_Tuple = True
            obj = list(obj)
        else: 
            # Otherwise just do a quick slice copy
            obj = obj[:]
            is_Tuple = False

        # Copy each item recursively
        for x in xrange(len(obj)):
            if type(obj[x]) in dignore:
                continue
            obj[x] = Copy(obj[x], use_deepcopy)

        if is_Tuple: 
            # Convert back into a Tuple again
            obj = Tuple(obj)

    Elif t == dict: 
        # Use the fast shallow dict copy() method and copy any 
        # values which aren't immutable (like lists, dicts etc)
        obj = obj.copy()
        for k in obj:
            if type(obj[k]) in dignore:
                continue
            obj[k] = Copy(obj[k], use_deepcopy)

    Elif t in dignore: 
        # Numeric or string/unicode? 
        # It's immutable, so ignore it!
        pass 

    Elif use_deepcopy: 
        obj = deepcopy(obj)
    return obj

if __== '__main__':
    import copy
    from time import time

    num_times = 100000
    L = [None, 'blah', 1, 543.4532, 
         ['foo'], ('bar',), {'blah': 'blah'},
         old_class(), new_class()]

    t = time()
    for i in xrange(num_times):
        Copy(L)
    print 'Custom Copy:', time()-t

    t = time()
    for i in xrange(num_times):
        Copy(L, use_deepcopy=False)
    print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t

    t = time()
    for i in xrange(num_times):
        copy.copy(L)
    print 'copy.copy:', time()-t

    t = time()
    for i in xrange(num_times):
        copy.deepcopy(L)
    print 'copy.deepcopy:', time()-t

    t = time()
    for i in xrange(num_times):
        L[:]
    print 'list slicing [:]:', time()-t

    t = time()
    for i in xrange(num_times):
        list(L)
    print 'list(L):', time()-t

    t = time()
    for i in xrange(num_times):
        [i for i in L]
    print 'list expression(L):', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(L)
    print 'list extend:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        for y in L:
            a.append(y)
    print 'list append:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(i for i in L)
    print 'generator expression extend:', time()-t
529
cryo

Я как мне сказали этот Python 3.3+ добавляет list.copy() метод, который должен быть таким же быстрым, как и нарезка:

newlist = old_list.copy()

132
anatoly techtonik

Какие есть варианты для клонирования или копирования списка в Python?

В Python 3 поверхностная копия может быть сделана с помощью:

a_copy = a_list.copy()

В Python 2 и 3 вы можете получить поверхностную копию с полным фрагментом оригинала:

a_copy = a_list[:]

Объяснение

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

Мелкая копия списка

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

Есть разные способы сделать это в Python 2 и 3. Пути Python 2 также будут работать в Python 3.

Python 2

В Python 2 идиоматический способ сделать поверхностную копию списка - это полный фрагмент оригинала:

a_copy = a_list[:]

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

a_copy = list(a_list)

но использование конструктора менее эффективно:

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

Python 3

В Python 3 списки получают метод list.copy:

a_copy = a_list.copy()

В Python 3.5:

>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125

Создание другого указателя не делает копию

Использование new_list = my_list затем изменяет new_list каждый раз, когда изменяется my_list. Почему это?

my_list это просто имя, которое указывает на фактический список в памяти. Когда вы говорите new_list = my_list, что вы не делаете копию, вы просто добавляете другое имя, которое указывает на этот оригинальный список в памяти. У нас могут быть похожие проблемы, когда мы делаем копии списков.

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

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

Глубокие копии

Чтобы сделать глубокая копия списка в Python 2 или 3, используйте deepcopy в модуле copy :

import copy
a_deep_copy = copy.deepcopy(a_list)

Чтобы продемонстрировать, как это позволяет нам создавать новые подсписки:

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

Итак, мы видим, что глубоко скопированный список - это совершенно другой список от оригинала. Вы можете свернуть свою собственную функцию - но не делайте. Скорее всего, вы будете создавать ошибки, которых не было бы, используя функцию Deepcopy стандартной библиотеки.

Не используйте eval

Вы можете увидеть это как способ глубокой копии, но не делайте этого:

problematic_deep_copy = eval(repr(a_list))
  1. Это опасно, особенно если вы оцениваете что-то из источника, которому не доверяете.
  2. Это ненадежно, если копируемый подэлемент не имеет представления, которое может быть вычислено для воспроизведения эквивалентного элемента.
  3. Это также менее производительно.

В 64-битной Python 2.7:

>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206

на 64-битной Python 3.5:

>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
113
Aaron Hall

Уже есть много ответов, которые говорят вам, как сделать правильную копию, но ни один из них не говорит, почему ваша оригинальная "копия" не удалась.

Python не хранит значения в переменных; это связывает имена с объектами. Ваше первоначальное назначение взяло объект, на который ссылается my_list, и также связало его с new_list. Независимо от того, какое имя вы используете, по-прежнему существует только один список, поэтому изменения, сделанные при обращении к нему как my_list, сохранятся при обращении к нему как new_list Каждый из остальных ответов на этот вопрос дает вам различные способы создания нового объекта для привязки к new_list.

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

new_list = list(my_list)  # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]

Чтобы продвинуть свой список на один шаг вперед, скопируйте каждый объект, к которому относится ваш список, и привяжите эти копии элементов к новому списку.

import copy  
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]

Это еще не полная копия, потому что каждый элемент списка может ссылаться на другие объекты, так же как список связан с его элементами. Для рекурсивного копирования каждого элемента в списке, а затем каждого другого объекта, на который ссылается каждый элемент, и т.д. Выполните глубокое копирование.

import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)

См. документация для получения дополнительной информации об угловых случаях при копировании.

49
jack

Используйте thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
31
Paul Tarjan

Идиома Python для этого - newList = oldList[:]

30
erisco

Сроки Python 3.6

Вот результаты синхронизации, используя Python 3.6.8. Имейте в виду, что это время относительно друг друга, а не абсолютное.

Я придерживался только создания мелких копий, а также добавил некоторые новые методы, которые были невозможны в Python2, такие как list.copy() (Python3 эквивалент фрагмента ) и две формы распаковка списка = (*new_list, = list и new_list = [*list]):

METHOD                  TIME TAKEN
b = [*a]                2.75180600000021
b = a * 1               3.50215399999990
b = a[:]                3.78278899999986  # Python2 winner (see above)
b = a.copy()            4.20556500000020  # Python3 "slice equivalent" (see above)
b = []; b.extend(a)     4.68069800000012
b = a[0:len(a)]         6.84498999999959
*b, = a                 7.54031799999984
b = list(a)             7.75815899999997
b = [i for i in a]      18.4886440000000
b = copy.copy(a)        18.8254879999999
b = []
for item in a:
  b.append(item)        35.4729199999997

Мы можем видеть, что победитель Python2 по-прежнему преуспевает, но не сильно вытесняет Python3 list.copy(), особенно учитывая превосходную читаемость последнего.

Темная лошадка - это метод распаковки и повторной упаковки (b = [*a]), который на ~ 25% быстрее, чем нарезка в сыром виде, и более чем в два раза быстрее, чем другой метод распаковки (*b, = a).

b = a * 1 также работает на удивление хорошо.

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


Вот код тестирования для заинтересованных сторон ( Шаблон отсюда ):

import timeit

COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'

print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []; for item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a:  b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
19
River

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

Хотя new_list = old_list[:], copy.copy(old_list)' и Py3k old_list.copy() работают для одноуровневых списков, они возвращаются к указанию на объекты list, вложенные в old_list и new_list, и изменения одного из объектов list сохраняются в другом.

Правка: Новая информация, представленная на свет

Как было указано обоими Аарон Холл и PM 2Ring с использованием eval() не только плохая идея, но и намного медленнее, чем copy.deepcopy() .

Это означает, что для многомерных списков единственным параметром является copy.deepcopy(). С учетом вышесказанного, это действительно не вариант, поскольку производительность снижается, когда вы пытаетесь использовать ее в многомерном массиве умеренного размера. Я попытался timeit, используя массив размером 42x42, что было неслыханно или даже слишком много для приложений биоинформатики, и я разочаровался в ожидании ответа и просто начал печатать мое редактирование в этом посте.

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

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

18
AMR

Давайте начнем с самого начала и немного углубимся в Explorer:

Итак, предположим, у вас есть два списка:

list_1=['01','98']
list_2=[['01','98']]

И мы должны скопировать оба списка, теперь начиная с первого списка:

Итак, сначала давайте попробуем по общему методу копирования:

copy=list_1

Теперь, если вы думаете, что копия скопировала list_1, то вы можете ошибаться, давайте проверим это:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

Результат:

4329485320
4329485320

Удивлен? Ok давайте рассмотрим это:

Так как мы знаем, что python ничего не хранит в переменной, переменные просто ссылаются на объект, а объект хранит значение. Здесь объект list, но мы создали две ссылки на этот же объект с двумя разными именами переменных. Итак, обе переменные указывают на один и тот же объект:

поэтому, когда вы делаете copy=list_1, что на самом деле он делает:

enter image description here

Здесь на изображении list_1 и copy два имени переменных, но объект одинаков для обеих переменных, list

Поэтому, если вы попытаетесь изменить скопированный список, он также изменит исходный список, потому что список там только один, вы будете изменять этот список независимо от того, делаете ли вы это из скопированного списка или из исходного списка:

copy[0]="modify"

print(copy)
print(list_1)

Результат:

['modify', '98']
['modify', '98']

Таким образом, он изменил оригинальный список:

Каково решение тогда?

Решение :

Теперь давайте перейдем ко второму Pythonic методу копирования списка:

copy_1=list_1[:]

Теперь этот метод исправляет то, с чем мы столкнулись в первом выпуске, давайте проверим это:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

Таким образом, мы можем видеть, что оба списка имеют разные идентификаторы, и это означает, что обе переменные указывают на разные объекты, поэтому на самом деле происходит следующее:

enter image description here

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

copy_1[0]="modify"

print(list_1)
print(copy_1)

Результат:

['01', '98']
['modify', '98']

Таким образом, как вы можете видеть, он не изменяет исходный список, он только изменяет скопированный список, так что мы в порядке.

Так что теперь я думаю, что мы закончили? подождите, мы тоже должны скопировать второй вложенный список, так что давайте попробуем Pythonic:

copy_2=list_2[:]

Итак, list_2 должен ссылаться на другой объект, который является копией list_2, давайте проверим:

print(id((list_2)),id(copy_2))

мы получаем вывод:

4330403592 4330403528

Теперь мы можем предположить, что оба списка указывают на разные объекты, поэтому теперь давайте попробуем изменить его и посмотрим, что он дает то, что нам нужно:

Итак, когда мы пытаемся:

copy_2[0][1]="modify"

print(list_2,copy_2)

это дает нам вывод:

[['01', 'modify']] [['01', 'modify']]

Теперь, это немного сбивает с толку, мы использовали Pythonic путь, и все же, мы сталкиваемся с той же проблемой.

давайте разберемся в этом:

Итак, когда мы делаем:

copy_2=list_2[:]

на самом деле мы копируем только внешний список, а не вложенный список, поэтому вложенный список является одним и тем же объектом для обоих списков, давайте проверим:

print(id(copy_2[0]))
print(id(list_2[0]))

Результат:

4329485832
4329485832

Так что на самом деле, когда мы делаем copy_2=list_2[:], вот что происходит:

enter image description here

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

Так в чем же решение?

Решение deep copy

from copy import deepcopy
deep=deepcopy(list_2)

Итак, теперь давайте проверим это:

print(id((list_2)),id(deep))

Результат:

4322146056 4322148040

оба идентификатора различны, теперь давайте проверим идентификатор вложенного списка:

print(id(deep[0]))
print(id(list_2[0]))

Результат:

4322145992
4322145800

Как видите, оба идентификатора различны, поэтому мы можем предположить, что оба вложенных списка теперь указывают на разные объекты.

Итак, когда вы делаете deep=deepcopy(list_2), что на самом деле происходит:

enter image description here

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

Теперь давайте попробуем изменить вложенный список и посмотрим, решил ли он предыдущую проблему или нет:

так что если мы сделаем:

deep[0][1]="modify"
print(list_2,deep)

Результат:

[['01', '98']] [['01', 'modify']]

Таким образом, как вы можете видеть, он не изменил исходный вложенный список, он только изменил скопированный список.

Если вам нравится мой подробный ответ, дайте мне знать, проголосовав за него, если у вас есть какие-либо сомнения, поняли этот ответ, прокомментируйте :)

18
Aaditya Ura

Меня удивляет, что это еще не было упомянуто, поэтому ради полноты ...

Вы можете выполнить распаковку списка с помощью "оператора сплат": *, который также скопирует элементы вашего списка.

old_list = [1, 2, 3]

new_list = [*old_list]

new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]

Очевидным недостатком этого метода является то, что он доступен только в Python 3.5+.

Тем не менее, это разумно, чем другие распространенные методы.

x = [random.random() for _ in range(1000)]

%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]

%timeit a = [*x]

#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
10
SCB

Обратите внимание, что в некоторых случаях, если вы определили свой собственный класс и хотите сохранить атрибуты, вам следует использовать copy.copy() или copy.deepcopy() вместо альтернатив, например в Python 3:

import copy

class MyList(list):
    pass

lst = MyList([1,2,3])

lst.name = 'custom list'

d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}


for k,v in d.items():
    print('lst: {}'.format(k), end=', ')
    try:
        name = v.name
    except AttributeError:
        name = 'NA'
    print('name: {}'.format(name))

Результаты:

lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
5
Chris_Rands

Очень простой подход, независимый от python версии, отсутствовал в уже заданных ответах, которые вы можете использовать большую часть времени (по крайней мере, я делаю):

new_list = my_list * 1       #Solution 1 when you are not using nested lists

Однако, если my_list содержит другие контейнеры (например, для вложенных списков), вы должны использовать deepcopy, как другие предложили в ответах выше из библиотеки копирования. Например:

import copy
new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists

.Бонус: Если вы не хотите копировать элементы, используйте (иначе: мелкая копия):

new_list = my_list[:]

Давайте поймем разницу между решением № 1 и решением № 2

>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55 
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])

Как видите, Решение № 1 работало идеально, когда мы не использовали вложенные списки. Давайте посмотрим, что произойдет, когда мы применим решение № 1 к вложенным спискам.

>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]   #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]       #Solution #2 - DeepCopy worked in nested list
5
jainashish
new_list = my_list[:]

new_list = my_list Попытайтесь понять это. Предположим, что my_list находится в куче памяти в местоположении X, т.е. my_list указывает на X. Теперь, присваивая new_list = my_list, вы позволяете new_list указывать на X. Это называется мелким копированием.

Теперь, если вы назначаете new_list = my_list[:], вы просто копируете каждый объект my_list в new_list. Это известно как Глубокая копия.

Другой способ сделать это:

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
3
Ravi Shankar

в python, если вы определили значение переменной и если вы переназначили эту переменную в другую,

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

>>> l = [1,2,3]
>>> k = l
>>> l[0] = 10
>>> l
[10, 2, 3]
>>> k
[10, 2, 3]

так что если вы измените что-либо в l & k, это отразится на обоих .. так что его ссылки друг на друга вместо того, чтобы справляться

для копирования используйте [::], чтобы оригинал не повлиял на выполнение задания.

>>> k = l[::]
>>> k
[10, 2, 3]
>>> l[0] = 100
>>> l
[100, 2, 3]
>>> k
[10, 2, 3]
0
Mohideen bin Mohammed