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

каковы варианты клонирования или копирования списка в Python?

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

18 ответов


С 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 первый.

  • если список содержит объекты, и вы хотите скопировать их, использовать общие 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]

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

  1. 10.59 sec (105.9 us / itn) -copy.deepcopy(old_list)
  2. 10.16 sec (101.6 us/itn) - чистый python Copy() метод копирования классов с помощью deepcopy
  3. 1.488 sec (14.88 us/itn) - чистый python Copy() метод не копирует классы (только дикты/списки/кортежи)
  4. 0.325 sec (3.25 us / itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17 us / itn) -[i for i in old_list] (a понимание)
  6. 0.186 sec (1.86 us / itn) -copy.copy(old_list)
  7. 0.075 sec (0.75 us / itn) -list(old_list)
  8. 0.053 sec (0.53 us / itn) -new_list = []; new_list.extend(old_list)
  9. 0.039 sec (0.39 us / 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 __name__ == '__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

редактировать: добавлены классы нового стиля, старого стиля и диктовки к бенчмаркам, а также сделана версия python намного быстрее и добавлены еще несколько методов, включая выражения списка и extend().


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

newlist = old_list.copy()


каковы варианты клонирования или копирования списка в 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

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

problematic_deep_copy = eval(repr(a_list))
  1. это опасно, особенно если вы оцениваете что-то из источника, которому не доверяете.
  2. это не надежно, если подэлемент, который вы копируете, не имеет представления, которое может быть eval'D для воспроизведения эквивалентного элемента.
  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

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

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)

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


new_list = list(old_list)


использовать thing[:]

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

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


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

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

Edit: новая информация выведена на свет

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

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

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

как есть может быть значительные проблемы с производительностью с помощью copy модуль copy.deepcopy для многомерных списков. попытка разработать другой способ копирования многомерного списка без использования deepcopy, (я работал над проблемой для курса, который позволяет запускать только 5 секунд для всего алгоритма, чтобы получить кредит), я придумал способ использовать встроенные функции, чтобы сделать копию вложенного списка, не имея их точки друг на друга или на list объекты, вложенные в них. Я использовал eval() и repr() в задании сделать копию старого списка в новый список без создания ссылки на старый список. Он принимает форму:

new_list = eval(repr(old_list))

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


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

такое заявление:

a = [1,2,3]

означает дать списку (объекту) имя a и так:

b = a

просто дает тот же объект a новое имя b, так что всякий раз, когда вы делаете что-то с a, объект изменяется и, следовательно,b изменения.

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

вы можете узнать больше об этом здесь.


Python 3.6.0 Тайминги

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

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

METHOD                  TIME TAKEN
b = a[:]                6.468942025996512   #Python2 winner
b = a.copy()            6.986593422974693   #Python3 "slice equivalent"
b = []; b.extend(a)     7.309216841997113
b = a[0:len(a)]         10.916740721993847
*b, = a                 11.046738261007704
b = list(a)             11.761539687984623
b = [i for i in a]      24.66165203397395
b = copy.copy(a)        30.853400873980718
b = []
for item in a:
  b.append(item)        48.19176080400939

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

обратите внимание, что эти методы делают не выходные эквивалентные результаты для любого ввода, кроме списков. все они работают для срезаемых объектов, некоторые работают для любой итерации, но только 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\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", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\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 = []\nfor 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))

давайте начнем с самого начала и исследуем его немного глубоко:

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

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

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

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

copy=list_1

теперь, если вы думаете, что copy скопировал 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

удивлен ? Хорошо, давайте рассмотрим его:

так как мы знаем, что 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']

так он изменил исходный список:

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

устранение :

теперь давайте перейдем ко второму подходящие для Python способ список копирования:

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 way:

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

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

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

выход:

4322145992
4322145800

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

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

enter image description here

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

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

Итак, если мы делаем :

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

выход:

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

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

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


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

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

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)

Не уверен, что это все еще актуально, но то же самое поведение справедливо и для словарей. Посмотрите на этот пример.

a = {'par' : [1,21,3], 'sar' : [5,6,8]}
b = a
c = a.copy()
a['har'] = [1,2,3]

a
Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

b
Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

c
Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}

обратите внимание, что в некоторых случаях, если вы определили свой собственный класс и хотите сохранить атрибуты, вы должны использовать 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

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)

очень простой подход, независимый от версии 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

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

newlist=list(oldlist)

Я думаю этот код поможет вам.