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

Как новичок Python, идущий с фона С++, оператор slicing в Python (3.4.x) выглядит мне смешно. Я просто не понимаю философию дизайна за "специальным правилом". Позвольте мне объяснить, почему я говорю это "особый".

С одной стороны, согласно ответу "Переполнение стека" здесь, оператор резки создает (глубокую) копию списка или части списка, т.е. новый список. Ссылка может быть старой (раньше, чем python 3.4.x), но я просто подтвердил поведение следующим простым экспериментом с python 3.4.2:

words = ['cat', 'window', 'defenestrate']
newList = words[:] # new objects are created; a.k.a. deep copy
newList[0] = 'dog'

print(words) # ['cat' ...
print(newList) # ['dog' ...

С другой стороны, согласно официальной документации здесь:

Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:
>>>

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters 
[]

Очевидно, что оператор нарезки [:] здесь не делает глубокой копии.

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

Итак, что может оправдать это "особое правило" в философии дизайна Python?

P.S. Если мой вывод неверен, есть только две возможности:

1, оператор "разрезания" Python на самом деле не является оператором, поэтому мое предположение не выполняется - тогда что это ( "оператор slicing" [:])?

2. Разница в поведении вызвана некоторым скрытым фактором, который не наблюдается. Расположение оператора резки (левая/правая сторона) относительно оператора присваивания случайно сосуществует с наблюдением за другим поведением. У них нет отношения причинности. Тогда каков скрытый фактор, который вызывает разницу в поведении?

Ответ 1

Операторы Python лучше всего рассматривать как синтаксический сахар для "магических" методов; например, x + y оценивается как x.__add__(y). Точно так же, как:

  • foo = bar.baz становится foo = bar.__getattr__(baz); тогда как
  • bar.baz = foo становится bar.__setattr__(baz, foo);

оператор "разрезания" Python * * a[b] оценивается как:

  • a.__getitem__(b); или
  • a.__setitem__(b, ...);

в зависимости от того, на какой стороне его присвоения; они не совсем одинаковы (см. также Как назначение работает с фрагментом списка python). Написано в "longhand", поэтому:

>>> x = [1, 2, 3]
>>> x.__getitem__(slice(None))  # ... = x[:]
[1, 2, 3]
>>> x.__setitem__(slice(None), (4, 5, 6))  # x[:] = ...
>>> x
[4, 5, 6]

документация по модели данных более подробно объясняет эти методы (например, __getitem__), и вы можете читать документы на slice.


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

>>> foo = [[], []]
>>> bar = foo[:]
>>> bar is foo
False  # outer list is new object
>>> bar[0] is foo[0]
True  # inner lists are same objects
>>> bar[0].append(1)
>>> foo
[[1], []]

* Ну, не строго operator.