Подтвердить что ты не робот

В чем разница между назначением среза, который разрезает весь список и прямое назначение?

Во многих местах я вижу назначение slice для list s. Я могу понять его использование при использовании с индексами (не по умолчанию), но я не могу понять его использование, например:

a_list[:] = ['foo', 'bar']

Чем отличается от

a_list = ['foo', 'bar']

?

4b9b3361

Ответ 1

a_list = ['foo', 'bar']

Создает новый list в памяти и указывает на него имя a_list. Не имеет значения, на что раньше указывал a_list.

a_list[:] = ['foo', 'bar']

Вызывает метод __setitem__ объекта a_list с slice в качестве индекс и новый list, созданный в памяти в качестве значения.

__setitem__ оценивает slice, чтобы выяснить, какие индексы он представляет, и вызывает iter значение, которое оно было передано. Затем он выполняет итерацию по объекту, устанавливая каждый индекс в диапазоне, указанном slice, на следующее значение от объекта. Для list s, если диапазон, указанный slice, не такой же длины, как и итерабельный, размер list изменяется. Это позволяет вам делать несколько интересных вещей, например удаление разделов списка:

a_list[:] = [] # deletes all the items in the list, equivalent to 'del a_list[:]'

или вставка новых значений в середине списка:

a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list

Однако с "расширенными срезами", где step не один, итерабельность должна быть правильной длины:

>>> lst = [1, 2, 3]
>>> lst[::2] = []
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
ValueError: attempt to assign sequence of size 0 to extended slice of size 2

Основными вещами, которые отличаются от назначения slice a_list, являются:

  • a_list должен указывать на объект
  • Этот объект изменен, вместо указания a_list на новый объект
  • Этот объект должен поддерживать __setitem__ с индексом slice
  • Объект справа должен поддерживать итерацию
  • На объекте справа не указывается имя. Если нет других ссылок на него (например, когда это буква, как в вашем примере), после завершения итерации это будет считаться ссылкой из.

Ответ 2

Разница довольно велика! В

a_list[:] = ['foo', 'bar']

Вы изменяете существующий список, привязанный к имени a_list. С другой стороны,

a_list = ['foo', 'bar']

назначает новый список имени a_list.

Возможно, это поможет:

a = a_list = ['foo', 'bar'] # another name for the same list
a_list = ['x', 'y'] # reassigns the name a_list
print a # still the original list

a = a_list = ['foo', 'bar']
a_list[:] = ['x', 'y'] # changes the existing list bound to a
print a # a changed too since you changed the object

Ответ 3

Назначая a_list[:], a_list ссылку на тот же объект списка, с измененным содержимым. Назначив a_list, a_list ссылку на новый объект списка.

Проверьте его id:

>>> a_list = []
>>> id(a_list)
32092040
>>> a_list[:] = ['foo', 'bar']
>>> id(a_list)
32092040
>>> a_list = ['foo', 'bar']
>>> id(a_list)
35465096

Как вы можете видеть, его id не изменяется с версией назначения slice.


Разные между двумя могут привести к совсем другому результату, например, когда список является параметром функции:

def foo(a_list):
    a_list[:] = ['foo', 'bar']

a = ['original']
foo(a)
print(a)

При этом также изменяется значение a, но если вместо этого использовалось a_list = ['foo', 'bar'], a остается его исходным значением.

Ответ 4

a_list = ['foo', 'bar']
a=a_list[:]  # by this you get an exact copy of a_list 
print(a)
a=[1,2,3] # even if you modify a it will not affect a_list
print(a)
print(a_list)