6

As a Python newbie coming from the C++ background, the slicing operator in Python (3.4.x) looks ridiculous to me. I just don't get the design philosophy behind the "special rule". Let me explain why I say it's "special".

On the one hand, according to the Stack Overflow answer here, the slicing operator creates a (deep) copy of a list or part of the list, i.e. a new list. The link may be old (earlier than python 3.4.x), but I just confirmed the behavior with the following simple experiment with 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' ...

On the other hand, according to the official documentation here:

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 
[]

Clearly, the slicing operator [:] does not do a deep copy here.

From the observation it seems to suggest that the slicing operator produces different behavior when it's on left/right side with respect to the assignment operator. I do not know any language in which an operator could produce similar behavior. After all, an operator is a function, just a syntactically special function, and a function's behavior should be self-contained, purely determined by all of its inputs.

So what can justify this "special rule" in Python design philosophy?

P.S. If my conclusion is not correct, there are really only two possibilities:

1, Python's slicing 'operator' is actually not an operator, so my assumption does not hold --- then what is it (the 'slicing operator' [:])?

2, The difference in behavior is caused by some latent factor not observed. The slicing operator's location (left/right hand side) with respect to the assignment operator accidentally co-exists with the observation of different behavior. They do not have causality relationship --- then what is the latent factor that causes the difference in behavior?

Community
  • 1
  • 1
h9uest
  • 10,958
  • 3
  • 18
  • 24
  • There's plenty about C++ that seems "ridiculous" to someone with a Python background. Please try to leave value judgments out of your questions. – Mark Ransom May 13 '15 at 17:31
  • *"according to the Stack Overflow answer here, the slicing operator creates a (deep) copy"*. Where does it say that? You linked to a question, btw, not an answer. – Stefan Pochmann May 13 '15 at 18:50
  • @MarkRansom What's wrong with the value judgement? Part of the question was on the design philosophy behind the design decisions. If the Python's decision was not 'ridiculous' to me, this question wouldn't exist in the first place. Be open to challenges and embrace different opinions. I'm perfectly fine with you finding certain C++ concepts ridiculous or even wrong. Just include you argument to support your assertions. – h9uest May 14 '15 at 09:49
  • @StefanPochmann Scroll down a little bit and you'll see "However, when you do newList = oldList[:], it "slices" the list, and creates a new list." in the accepted answer. – h9uest May 14 '15 at 09:53
  • Sorry, I was unclear. What I meant was the "deep". That answer doesn't say it's a deep copy. – Stefan Pochmann May 14 '15 at 09:58
  • @StefanPochmann "Therefore, it creates a new list with all the data contained in the first one, but both can be altered without changing the other." --- this is deep copy. The author just did not use the term. – h9uest May 14 '15 at 10:10
  • @h9uest it **is not** a deep copy - it is a shallow copy, but that doesn't matter because *the list only contains immutable objects*. I have [commented on that answer](http://stackoverflow.com/questions/323689/python-list-slice-syntax-used-for-no-obvious-reason#comment48571453_323733) to this effect; I think it's a little misleading as currently written. – jonrsharpe May 14 '15 at 10:12
  • Yes. I got it wrong. Sorry about the confusion. It's shallow copy. – h9uest May 14 '15 at 10:15

1 Answers1

11

Python operators are best considered as syntactic sugar for "magic" methods; for example, x + y is evaluated as x.__add__(y). In the same way that:

  • foo = bar.baz becomes foo = bar.__getattr__(baz); whereas
  • bar.baz = foo becomes bar.__setattr__(baz, foo);

the Python "slicing operator" * a[b] is evaluated as either:

  • a.__getitem__(b); or
  • a.__setitem__(b, ...);

depending on which side of the assignment it's on; the two aren't quite the same (see also How assignment works with python list slice). Written out in "longhand", therefore:

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

The data model documentation explains these methods in more detail (e.g. __getitem__), and you can read the docs on slice, too.


Note that the slice is a shallow copy, not a deep one, as the following demonstrates:

>>> 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], []]

* Well, not strictly an operator.

Community
  • 1
  • 1
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Thanks for the great answer. One question about the "shallow copy" though: what's going on with my experiment attached(the 'cat' 'dog' test)? It's clearly a deep copy. – h9uest May 14 '15 at 10:07
  • 2
    @h9uest I'm not sure why you think your test shows it as *"clearly a deep copy"*. You have a mutable sequence of immutable objects, so it's impossible to tell from *any* demonstration on that object whether a given copying operation (`[:]` or anything else) is deep or shallow (note that, by contrast, my demo is on a mutable sequence *of mutable sequences*). See e.g. https://docs.python.org/2/library/copy.html, http://stackoverflow.com/q/17246693/3001761 for further explanation on the difference. – jonrsharpe May 14 '15 at 10:10