Если утверждение меняет себя [дубликат]

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

Вы можете выполнить распаковку списка с помощью оператора «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)
6
задан Tshepang 23 August 2014 в 07:57
поделиться

6 ответов

в for obj in myList:, на каждой итерации obj является (неглубокой) копией элемента в myList. Таким образом, изменение на obj ничего не делает для элементов myList.

Это отличается от Perl for my $obj (@myList) {}

5
ответ дан Ade YU 20 August 2018 в 18:28
поделиться
  • 1
    Именно сейчас я это понимаю. obj не является итератором, как в C ++, это в основном копия объекта, которая игнорируется в следующей итерации. Таким образом, модификация может быть выполнена только при использовании доступа к глобальному / прямому списку. – RobW 29 February 2012 в 11:38
  • 2
    @RobW, obj не является копией, и этот ответ вводит в заблуждение. obj - как и все переменные в Python - больше похож на указатель на C / C ++. См. Редактирование на мой ответ . – senderle 29 February 2012 в 16:27
  • 3
    Ade YU, я собираюсь, когда вы говорите «копировать». вы имеете в виду & quot; копию адреса элемента & quot; а не «копирование самого элемента». Вы можете это уточнить. – senderle 29 February 2012 в 16:29
  • 4
    @senderle Да. В Python переменные являются просто ссылками на objects . Скопированы только переменные , но objects . Это как obj = myList[index] произошло в самом начале каждой итерации. Поэтому obj += 1 не влияет на myList[index]. Спасибо. Я улучшу свое заявление о ответе. – Ade YU 29 February 2012 в 16:51
  • 5
    может быть не мелкой копией, если это список списков – Ninja420 14 April 2017 в 01:29

Я думаю, вы неправильно поняли, что такое «объект итератора». Цикл 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 - никаких побочных эффектов не может быть, потому что указанная вещь неизменна.

4
ответ дан Community 20 August 2018 в 18:28
поделиться
  • 1
    +1 для перечисления – Fred 23 February 2012 в 16:19
  • 2
    Очевидно, print a должен быть print myList, я исправил это. Спасибо за указатель enumerate, очень полезный, избегает поддержки собственного кода для индекса списка! – RobW 29 February 2012 в 11:45
  • 3
    Чтобы быть еще более питоническим и amp; лаконично, вы можете сделать либо [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 - переменная, которая содержит объект в списке. Это все.

1
ответ дан Marcin 20 August 2018 в 18:28
поделиться
  • 1
    Если obj будет итератором, как в C ++, тогда объект списка будет обновлен. Но, по-видимому, obj является копией, и после каждой итерации изменения игнорируются. По-видимому, Python делает последнее, что является моим вопросом. – RobW 29 February 2012 в 11:44
  • 2
    @RobW: Повторите за мной: в этом примере кода нет копий. 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

Это работает.

0
ответ дан Matt Alcock 20 August 2018 в 18:28
поделиться
  • 1
    Это действительно то, что я написал и ничего не ответил. – RobW 29 February 2012 в 11:42

В первом примере целое копируется в obj, который увеличивается на 1. Список не изменяется.

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

0
ответ дан Michel Keijzers 20 August 2018 в 18:28
поделиться

Причина 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]
6
ответ дан NPE 20 August 2018 в 18:28
поделиться
  • 1
    Спасибо за Ваш ответ. Я уже пришел к выводу, что итератор obj не является итератором, как в C ++, а изменение объекта не изменяет список. Вы говорите, что obj снова привязан к новому объекту, который будет потерян в следующей итерации. Очистить! – RobW 29 February 2012 в 11:41
  • 2
    Отличный ответ! Речь идет не о «мелкой копии», о которой говорится в принятом ответе. – Pei 29 October 2015 в 00:08
Другие вопросы по тегам:

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