Меня удивляет, что это еще не упоминалось, поэтому для полноты ...
Вы можете выполнить распаковку списка с помощью оператора «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)
в for obj in myList:
, на каждой итерации obj
является (неглубокой) копией элемента в myList
. Таким образом, изменение на obj
ничего не делает для элементов myList
.
Это отличается от Perl for my $obj (@myList) {}
Я думаю, вы неправильно поняли, что такое «объект итератора». Цикл for
не является объектом итератора. Для всех целей и целей такой цикл цикла:
myList = [0, 1, 2, 3, 4]
for x in myList:
print x
делает это (но более эффективно и менее подробно):
i = 0
while i < len(myList)
x = myList[i]
print x
i += 1
Итак, вы видите, что любые изменения сделаны на x
теряются, как только начинается следующий цикл, потому что значение x
перезаписывается значением следующего элемента в списке.
Как и другие наблюдатели, можно изменить значение списка при его итерации по нему. (Но не изменяйте его длину! Вот где вы попадаете в неприятности.) Один из элегантных способов сделать это выглядит следующим образом:
for i, x in enumerate(myList):
myList[i] = some_func(x)
Обновление: также важно понимать, что нет копирования продолжается в цикле for. В приведенном выше примере i
и x
- как и все переменные в Python - больше похожи на указатели в C / C ++. По мере продвижения цикла for obj
указывает на myList[0]
, myList[1]
и т. Д., В свою очередь. И как указатель C / C ++, свойства объекта, на который указывает, не изменяются при изменении указателя. Но также как и указатель C, вы можете напрямую изменить указав на вещь, потому что это не копия. В C это выполняется с помощью разыменования указателя; в Python это делается с помощью изменяемого объекта. Вот почему работает ответ NPE . Если i
и x
были даже неглубокими копиями, было бы невозможно делать то, что он делает.
Причина, по которой вы не можете напрямую изменить int
так, как вы можете изменить list
s (как в ответе NPE), заключается в том, что int
s не изменяются. Когда объект 5
создается, ничто не может изменить его значение. Вот почему прохождение вокруг указателя 5
безопасно в Python - никаких побочных эффектов не может быть, потому что указанная вещь неизменна.
print a
должен быть print myList
, я исправил это. Спасибо за указатель enumerate
, очень полезный, избегает поддержки собственного кода для индекса списка!
– RobW
29 February 2012 в 11:45
[some_func(x) for x in myList]
, либо map(some_func, myList)
, хотя они делают копии исходного списка.
– Ryan Madsen
26 February 2013 в 03:34
Вы смущены. Рассмотрим ваш первый фрагмент:
myList = [1, 2, 3, 4, 5]
for obj in myList:
obj += 1
print a
obj
не является каким-то волшебным указателем в списке. Это переменная, которая содержит ссылку на объект, который также имеет место в myList. obj += 1
влияет на увеличение значения, сохраненного в obj
. Ваш код затем ничего не делает с этим значением.
Чтобы быть ясным: в этом примере кода нет копий. obj - переменная, которая содержит объект в списке. Это все.
obj
будет итератором, как в C ++, тогда объект списка будет обновлен. Но, по-видимому, obj
является копией, и после каждой итерации изменения игнорируются. По-видимому, Python делает последнее, что является моим вопросом.
– RobW
29 February 2012 в 11:44
obj
- это переменная, которая содержит объект в списке. Вот и все.
– Marcin
29 February 2012 в 12:29
Модификация в списке разрешена. Ваши примеры кода arbove довольно искажены ...
myList = [1, 2, 3, 4, 5]
for index in range(0,len(myList)):
myList[index] += 1
print myList
Это работает.
В первом примере целое копируется в obj, который увеличивается на 1. Список не изменяется.
Если вы будете использовать экземпляр класса и выполнять операции над ним, он будет изменен.
Причина obj += 1
не делает то, что вы ожидаете, так это то, что этот оператор не изменяет obj
на месте. Вместо этого он вычисляет новое значение, а переупорядочивает переменную obj
, чтобы указать на новое значение. Это означает, что содержимое списка остается неизменным.
В общем случае есть , возможно изменить список, итерации по нему с помощью for obj in myList
. Например:
myList = [[1], [2], [3], [4], [5]]
for obj in myList:
obj[0] += 1
print(myList)
Это выдает:
[[2], [3], [4], [5], [6]]
Разница между этим и вашим первым примером заключается в том, что здесь список содержит mutable объекты, а код изменяет эти объекты на месте.
Обратите внимание, что можно также написать цикл, используя понимание списка:
myList = [val+1 for val in myList]
obj
не является итератором, как в C ++, а изменение объекта не изменяет список. Вы говорите, что obj
снова привязан к новому объекту, который будет потерян в следующей итерации. Очистить!
– RobW
29 February 2012 в 11:41
obj
не является итератором, как в C ++, это в основном копия объекта, которая игнорируется в следующей итерации. Таким образом, модификация может быть выполнена только при использовании доступа к глобальному / прямому списку. – RobW 29 February 2012 в 11:38obj
не является копией, и этот ответ вводит в заблуждение. obj - как и все переменные в Python - больше похож на указатель на C / C ++. См. Редактирование на мой ответ . – senderle 29 February 2012 в 16:27obj = myList[index]
произошло в самом начале каждой итерации. Поэтомуobj += 1
не влияет наmyList[index]
. Спасибо. Я улучшу свое заявление о ответе. – Ade YU 29 February 2012 в 16:51