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

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

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

+2227
10 апр. '10 в 8:49
источник поделиться
24 ответа

С 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)
    
  • Вы можете использовать общий 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]
+2958
10 апр. '10 в 8:55
источник

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

  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] (понимание списка)
  6. 0,186 с (1,86USN/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 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
+549
10 апр. '10 в 10:16
источник
другие ответы

Связанные вопросы


Похожие вопросы

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

newlist = old_list.copy()

+138
23 июл. '13 в 12:32
источник

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

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

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

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

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

В 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
+120
25 окт. '14 в 12:13
источник

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

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)

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

+51
23 нояб. '14 в 16:45
источник

new_list = list(old_list)

+35
10 апр. '10 в 9:03
источник

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

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
+34
10 апр. '10 в 8:53
источник

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

+32
10 апр. '10 в 8:53
источник

Сроки Python 3.6

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

Я придерживался только мелкого копирования, а также добавил некоторые новые методы, которые не были возможны в Python2, такие как list.copy() (эквивалент фрагмента Python3 slice equivalent) и две формы распаковки списка (*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))
+22
05 апр. '17 в 1:01
источник

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

Итак, у вас есть два списка:

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

Удивлен? Хорошо, пусть исследует это:

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

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

введите описание изображения здесь

Здесь в списке image_1 и копировании находятся два имени переменной, но объект одинаковый для обеих переменных, который равен list

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

copy[0]="modify"

print(copy)
print(list_1)

выход:

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

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

Что такое решение?

Решение:

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

copy_1=list_1[:]

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

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

4338792136
4338791432

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

введите описание изображения здесь

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

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']]

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

понять это:

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

copy_2=list_2[:]

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

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

выход:

4329485832
4329485832

Итак, когда мы делаем copy_2=list_2[:], это происходит:

введите описание изображения здесь

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

Итак, каково решение?

Решение 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), что на самом деле происходит:

введите описание изображения здесь

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

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

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

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

выход:

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

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

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

+21
13 нояб. '17 в 7:04
источник

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

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

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

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

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

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

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

+18
10 июл. '15 в 3:51
источник

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

Это утверждение:

a = [1,2,3]

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

b = a

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

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

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

+18
23 мар. '17 в 12:32
источник

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

Вы можете выполнить распаковку списка с помощью оператора "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)
+11
26 февр. '18 в 2:33
источник

Обратите внимание, что в некоторых случаях, если вы определили свой собственный пользовательский класс и хотите сохранить атрибуты, вы должны использовать 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
+6
16 мая '18 в 14:31
источник

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

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]}
+5
08 сент. '17 в 8:39
источник

Очень простой подход, не зависящий от версии 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
01 нояб. '17 в 8:08
источник

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

newlist=list(oldlist)

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

+5
15 нояб. '17 в 13:17
источник
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. Это называется Deep copy.

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

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
+3
26 июн. '17 в 21:03
источник

Вы можете использовать встроенный list.copy() (python 3. 3+): https://docs.python.org/3/library/copy.html new_list = old_list.copy()

+1
05 мар. '19 в 17:13
источник

Вам понравится использовать deepcopy из стандартной библиотеки python.

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

my_lst=[1,2,3,4,5] #Python list
print my_lst, ' my_lst (before copy)'

my_lst_copy = my_lst=[1,2,3,4,5] #Simple copy of python list
my_lst_copy[2] = 55 #Copy of python list changed

print my_lst_copy, ' my_lst_copy (copy of python list)'
print my_lst, ' my_lst (after copy)'

>>>[1, 2, 3, 4, 5]  my_lst (before copy)
>>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
>>>[1, 2, 55, 4, 5]  my_lst (after copy)

Как вы уже заметили, и как вы еще раз заметили в приведенном выше примере, измените любой элемент скопированного списка. my_list_cp изменяет исходный список my_list. Причина этого заключается в том, что не было нового назначения для my_list_cp.

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

from copy import deepcopy

my_lst=[1,2,3,4,5] #Python list
print my_lst, ' my_lst (before copy)'

my_lst_copy = deepcopy(my_lst) #Python list copied
my_lst_copy[2] = 55 #Copy of python list changed

print my_lst_copy, ' my_lst_copy (copy of python list)'
print my_lst, ' my_lst (after copy)'

>>>[1, 2, 3, 4, 5]  my_lst (before copy)
>>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
>>>[1, 2, 3, 4, 5]  my_lst (after copy)

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

0
03 дек. '18 в 16:28
источник

в 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
14 мая '19 в 5:06
источник

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

В основе любой функции глубокого копирования лежит способ создания мелкой копии. Как? Просто. Любая функция глубокого копирования только дублирует контейнеры неизменяемых объектов. Когда вы глубоко копируете вложенный список, вы дублируете только внешние списки, а не изменяемые объекты внутри списков. Вы только дублируете контейнеры. То же самое работает и для классов. Когда вы копируете класс глубоко, вы копируете все его изменяемые атрибуты. Так как? Почему вам нужно только копировать контейнеры, такие как списки, диктанты, кортежи, iters, классы и экземпляры классов?

Это просто. Изменчивый объект не может быть дублирован. Его нельзя изменить, поэтому это только одно значение. Это означает, что вам никогда не придется дублировать строки, числа, bools или любые другие. Но как бы вы продублировали контейнеры? Просто. Вы просто инициализируете новый контейнер со всеми значениями. Deepcopy опирается на рекурсию. Он дублирует все контейнеры, даже те, в которых есть контейнеры, до тех пор, пока не останется ни одного контейнера. Контейнер является неизменным объектом.

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

def deepcopy(x):
  immutables = (str, int, bool, float)
  mutables = (list, dict, tuple)
  if isinstance(x, immutables):
    return x
  elif isinstance(x, mutables):
    if isinstance(x, tuple):
      return tuple(deepcopy(list(x)))
    elif isinstance(x, list):
      return [deepcopy(y) for y in x]
    elif isinstance(x, dict):
      values = [deepcopy(y) for y in list(x.values())]
      keys = list(x.keys())
      return dict(zip(keys, values))

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

Примеры

Скажем, у вас есть этот список: [1, 2, 3]. Неизменяемые числа не могут быть дублированы, но другой слой может. Вы можете продублировать его, используя понимание списка: [x для x в [1, 2, 3]

Теперь представьте, что у вас есть этот список: [[1, 2], [3, 4], [5, 6]]. На этот раз вы хотите создать функцию, которая использует рекурсию для глубокого копирования всех слоев списка. Вместо предыдущего понимания списка:

[x for x in _list]

Он использует новый для списков:

[deepcopy_list(x) for x in _list]

И deepcopy_list выглядит так:

def deepcopy_list(x):
  if isinstance(x, (str, bool, float, int)):
    return x
  else:
    return [deepcopy_list(y) for y in x]

Теперь у вас есть функция, которая может копировать любой список strs, bools, floast, ints и даже списков на бесконечное число слоев, используя рекурсию. И вот, у вас это есть, глубокий копирование.

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

0
08 сент. '19 в 2:25
источник

в 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]
-1
30 апр. '19 в 7:07
источник

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

new_list = list(''.join(my_list))
-5
03 дек. '17 в 1:03

Посмотрите другие вопросы по меткам или Задайте вопрос