Различные поведения нарезки с левой или правой стороны оператора присваивания
Как новичок 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.