Полностью удален из java 8 + Частично удален из java 7 (например, интернированные строки) source
С 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]
Каковы варианты клонирования или копирования списка в Python?
blockquote>В 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. Почему это?
blockquote>
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))
- Это опасно, особенно если вы оцениваете что-то из источника, которому вы не доверяете.
- Это не надежный, если подэлемент, который вы копируете, не имеет представления, которое может быть доказано для воспроизведения эквивалентного элемента.
- Он также менее эффективен.
В 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
вы можете использовать встроенную функцию list ():
newlist=list(oldlist)
Я думаю, этот код вам поможет.
Давайте начнем с начала и исследователя немного глубже:
blockquote>Итак, у вас есть два списка:
list_1=['01','98'] list_2=[['01','98']]
И мы должны скопируйте оба списка, начиная с первого списка:
Итак, сначала попробуем общий метод копирования:
copy=list_1
Теперь, если вы думаете, что копия скопировала список_1, вы можете Неправильно, давайте проверим:
blockquote>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']
Так что он изменил Исходный список:
Что такое решение?
Решение:
blockquote>Теперь перейдем ко второму питоническому методу копирования списка :
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']]
Итак, вы можете видеть, что он не изменил исходный вложенный список, он только изменил скопированный список.
Если вам понравился мой подробный ответ, сообщите мне об этом, если вы сомневаетесь в этом ответе, прокомментируйте:)
В отличие от других языков, имеющих переменную и значение, у Python есть имя и объект.
Этот оператор:
a = [1,2,3]
означает присвоение списку (объекту) имени a
, и это:
b = a
просто дает тому же объекту a
новое имя b
, поэтому всякий раз, когда вы что-то делаете с a
, объект изменяется, и поэтому b
изменяется .
Единственный способ сделать действительно копию a для создания нового объекта, как и другие ответы, уже сказал.
Вы можете увидеть больше об этом здесь .
Не уверен, что это все еще актуально, но такое же поведение имеет место и для словарей. Посмотрите на этот пример.
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
Все другие участники дали отличные ответы, которые работают, когда у вас есть один размерный (выровненный) список, однако из упомянутых выше методов, только 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, не неслыханный или даже такой большой для приложений для биоинформатики, и я отказался от ожидания ответа и только начал набирать свое редактирование на этот пост.кажется, что единственным реальным вариантом является инициализация нескольких списков и работа над ними независимо.
blockquote>Как указывали другие, может быть значимыми проблемы с производительностью. Если у кого-то есть другие предложения, как обрабатывать многомерное копирование списков, используя модуль
copy
иcopy.deepcopy
для многомерных списков . Попытка разработать другой способ копирования многомерного списка без использованияdeepcopy
(я работал над проблемой для курса, который позволяет всего 5 секунд для запуска всего алгоритма для получения кредита), я придумал способ использовать встроенные функции для создания копии вложенного списка, не указывая друг на друга или на объектыlist
, вложенные в них. Я использовалeval()
иrepr()
в присваивании, чтобы сделать копию старого списка в новый список, не создавая ссылку на старый список. Он принимает форму:В основном, это делает представлениеnew_list = eval(repr(old_list))
old_list
в виде строки, а затем оценивает строку, как если бы это был объект, который представляет строка. При этом никакая ссылка на исходный объектlist
не производится. Создается новый объектlist
, и каждая переменная указывает на свой собственный независимый объект. Вот пример использования 2-мерного вложенного списка.Если вы затем проверите содержимое каждого списка, например, список 4 на 3, Python вернет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
. Хотя это, вероятно, не канонический или синтаксически правильный способ сделать это, похоже, что он работает хорошо. Я не тестировал производительность, но я собираюсь предположить, что для>>> 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
.
repr()
, достаточна для повторного создания объекта. Кроме того, eval()
- инструмент последней инстанции; см. Эваль действительно опасен ветеран SO Нед Батчелдер для деталей. Поэтому, когда вы выступаете за использование eval()
, вы действительно i> должны упоминать, что это может быть опасно.
– PM 2Ring
10 July 2015 в 14:51
eval()
в Python в целом является риском. Это не так много, независимо от того, используете ли вы функцию в коде, но что это дыра безопасности в Python сама по себе. Мой пример не использует его с функцией, которая получает входные данные из input()
, sys.agrv
или даже текстового файла. Это больше похоже на инициализацию пустого многомерного списка один раз, а затем просто способ копирования в цикле вместо повторной инициализации на каждой итерации цикла.
– AMR
10 July 2015 в 16:41
new_list = eval(repr(old_list))
, поэтому, кроме того, что это плохая идея, возможно, слишком медленная работа.
– AMR
10 July 2015 в 17:19
Идиома Python для этого - newList = oldList[:]
Феликс уже дал отличный ответ, но я думал, что сделаю сравнение скорости различных методов:
copy.deepcopy(old_list)
Copy()
, копирующий классы с глубокой копией Copy()
метод не копирует классы (только dicts / lists / tuples) for item in old_list: new_list.append(item)
[i for i in old_list]
(понимание списка ) copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
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()
.
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] см. документацию .
Очень простой подход, не зависящий от версии 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
Используйте thing[:]
>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>>
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)
Вот результаты синхронизации с использованием 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))
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
Меня удивляет, что это еще не упоминалось, поэтому для полноты ...
Вы можете выполнить распаковку списка с помощью оператора «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)
Мне сказали , что Python 3.3+ добавляет метод list.copy()
, который должен быть таким же быстрым, как нарезка:
newlist = old_list.copy()
list.copy
(доступный с Python 3.3)? Если вам не нужна совместимость с Python 2, для этого действительно нужен One Obvious Way ™. – Mark Dickinson 5 January 2018 в 09:31newlist = [*mylist]
также есть возможность в Python 3.newlist = list(mylist)
, возможно, более ясно. – Stéphane 1 July 2018 в 22:23