как изменить значение словаря python [duplicate]

UPDATE table_name 
SET field = replace(field, 'string-to-find', 'string-that-will-replace-it');
1801
задан Taryn 22 March 2017 в 17:15
поделиться

19 ответов

С 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.
  • Если список содержит объекты, и вы также хотите их скопировать, используйте 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]
2346
ответ дан Aran-Fey 18 August 2018 в 11:44
поделиться
  • 1
    @FelixKling: Имеет смысл отредактировать этот ответ, чтобы упомянуть метод list.copy (доступный с Python 3.3)? Если вам не нужна совместимость с Python 2, для этого действительно нужен One Obvious Way ™. – Mark Dickinson 5 January 2018 в 09:31
  • 2
    @FelixKling Я 100% согласен. Для ответа на важный вопрос Python этот бит немного разбросан и устарел. – Jiminion 20 May 2018 в 19:05
  • 3
    Если я не ошибаюсь: newlist = [*mylist] также есть возможность в Python 3. newlist = list(mylist), возможно, более ясно. – Stéphane 1 July 2018 в 22:23
  • 4
    Другая возможность - new_list = old_list * 1 – aris 2 August 2018 в 16:13
  • 5

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

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

Используя 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

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

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
88
ответ дан Aaron Hall 18 August 2018 в 11:44
поделиться

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

newlist=list(oldlist)

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

2
ответ дан Akash Nayak 18 August 2018 в 11:44
поделиться

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

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

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

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

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

copy=list_1

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

output:

4329485320
4329485320

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

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

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

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

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

copy[0]="modify"

print(copy)
print(list_1)

output:

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

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

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

Решение:

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

copy_1=list_1[:]

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

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

4338792136
4338791432

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

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

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

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

давайте поймем это:

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

copy_2=list_2[:]

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

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

output:

4329485832
4329485832

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

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

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

Решение - 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]))

output:

4322145992
4322145800

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

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

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

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

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

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

вывод:

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

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

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

10
ответ дан Ayodhyankit Paul 18 August 2018 в 11:44
поделиться

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

Этот оператор:

a = [1,2,3]

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

b = a

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

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

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

12
ответ дан Azeem 18 August 2018 в 11:44
поделиться

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

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]}
4
ответ дан Bobesh 18 August 2018 в 11:44
поделиться

Обратите внимание, что есть случаи, когда вы определили свой собственный пользовательский класс и хотите сохранить атрибуты, тогда вы должны использовать 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
3
ответ дан Chris_Rands 18 August 2018 в 11:44
поделиться

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

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

Редактирование: новая информация, отображаемая

Как указывалось как Aaron Hall , так и 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 в виде строки, а затем оценивает строку, как если бы это был объект, который представляет строка. При этом никакая ссылка на исходный объект list не производится. Создается новый объект list, и каждая переменная указывает на свой собственный независимый объект. Вот пример использования 2-мерного вложенного списка.
old_list = [[0 for j in range(y)] for i in range(x)] # initialize (x,y) nested list

# assign a copy of old_list to new list without them pointing to the same list object
new_list = eval(repr(old_list)) 

# make a change to new_list 
for j in range(y):
    for i in range(x):
    new_list[i][j] += 1
Если вы затем проверите содержимое каждого списка, например, список 4 на 3, Python вернет
>>> new_list

[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

>>> old_list

[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
. Хотя это, вероятно, не канонический или синтаксически правильный способ сделать это, похоже, что он работает хорошо. Я не тестировал производительность, но я собираюсь предположить, что для eval() и rep() будет меньше накладных расходов, чем deepcopy.

18
ответ дан Community 18 August 2018 в 11:44
поделиться
  • 1
    Это не всегда будет работать, поскольку нет гарантии, что строка, возвращаемая repr(), достаточна для повторного создания объекта. Кроме того, eval() - инструмент последней инстанции; см. Эваль действительно опасен ветеран SO Нед Батчелдер для деталей. Поэтому, когда вы выступаете за использование eval(), вы действительно должны упоминать, что это может быть опасно. – PM 2Ring 10 July 2015 в 14:51
  • 2
    Честная оценка. Хотя я думаю, что точка Батчелдера заключается в том, что наличие функции eval() в Python в целом является риском. Это не так много, независимо от того, используете ли вы функцию в коде, но что это дыра безопасности в Python сама по себе. Мой пример не использует его с функцией, которая получает входные данные из input(), sys.agrv или даже текстового файла. Это больше похоже на инициализацию пустого многомерного списка один раз, а затем просто способ копирования в цикле вместо повторной инициализации на каждой итерации цикла. – AMR 10 July 2015 в 16:41
  • 3
    Как отметил @AaronHall, вероятно, значительная проблема с производительностью при использовании new_list = eval(repr(old_list)), поэтому, кроме того, что это плохая идея, возможно, слишком медленная работа. – AMR 10 July 2015 в 17:19

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

26
ответ дан erisco 18 August 2018 в 11:44
поделиться

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

  1. 10,59 сек (105,9us / itn) - copy.deepcopy(old_list)
  2. 10.16 сек (101.6us / itn) - метод чистого питона Copy(), копирующий классы с глубокой копией
  3. 1.488 сек (14.88us / itn) - чистый питон Copy() метод не копирует классы (только dicts / lists / tuples)
  4. 0,325 с (3,25us / itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17us / itn) - [i for i in old_list] (понимание списка )
  6. 0,186 с (1,86us / itn) - copy.copy(old_list)
  7. 0,075 сек (0,75 us / 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[:] ( list slicing )

Таким образом, самая быстрая сортировка списка. Но имейте в виду, что 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

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

449
ответ дан Gabriel Staples 18 August 2018 в 11:44
поделиться
  • 1
    Поскольку вы проводите бенчмаркинг, может оказаться полезным включить контрольную точку. Являются ли эти цифры точными в 2017 году с использованием Python 3.6 с полностью скомпилированным кодом? Я отмечаю ответ ниже ( stackoverflow.com/a/17810305/26219 ) уже задает этот ответ. – Mark Edington 3 April 2017 в 19:52
  • 2
    используйте модуль timeit. Кроме того, вы не можете заключить много из таких микро-тестов, как это. – Corey Goldberg 31 March 2018 в 21:29

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

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)

Для получения дополнительной информации о копировании в окне [gg] см. документацию .

42
ответ дан jack 18 August 2018 в 11:44
поделиться

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

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

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

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

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

new_list = my_list[:]

Давайте понимать разницу между решением # 1 и Solution # 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
2
ответ дан jainashish 18 August 2018 в 11:44
поделиться

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

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
27
ответ дан Paul Tarjan 18 August 2018 в 11:44
поделиться
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)
2
ответ дан Ravi Shankar 18 August 2018 в 11:44
поделиться

Python 3.6.0 Timings

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

Я придерживался только мелких копий, а также добавил некоторые новые методы, которые не были возможны в Python2, например list.copy() ( Python3 эквивалент среза ) и распаковки (*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().

Обратите внимание, что эти методы делают not выводными эквивалентными результатами для любого ввода, отличного от списков. Все они работают для разрезаемых объектов, некоторые работы для любого итерабельного, но только 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))
116
ответ дан River 18 August 2018 в 11:44
поделиться
  • 1
    Кажется, они оптимизировали инициализатор list в Python 3.6.1. У меня нет установки Python 3.6.0, но b = list(a) получает 2.7 и b = a[:] получает 3.1, а b = a.copy() получает 3.1 (на моей Windows и Linux с CPython 3.6.1) поэтому list() примерно на 10% быстрее – Artyer 9 August 2017 в 14:49
  • 2
    @Artyer Я снова тестировал Python 3.6.3 (WSL 16.04) и получил в основном тот же порядок – River 12 November 2017 в 23:47

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

Вы можете выполнить распаковку списка с помощью оператора «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)
7
ответ дан SCB 18 August 2018 в 11:44
поделиться

new_list = list(old_list)

30
ответ дан user285176 18 August 2018 в 11:44
поделиться
116
ответ дан River 6 September 2018 в 23:23
поделиться
120
ответ дан River 30 October 2018 в 03:59
поделиться
Другие вопросы по тегам:

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