17

We can (shallow) copy a list by using [:]:

l = [1, 2, 3]
z1 = l[:]

We can also (shallow) copy it by using [::]:

z2 = l[::]

and now z1 == z2 will be True. I understand how these slices work after reading the answers in Explain Python's slice notation.

But, my question is, is there any difference between these two internally? Is one more efficient than the other in copying or do they do exactly the same things?

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
user6774416
  • 756
  • 5
  • 18
  • 7
    It's the first colon that makes it a slice, the second doesn't change anything. You could come up with various other options (`[0:]`, `[::1]`, ...) but they do the same thing. – jonrsharpe Jan 14 '17 at 10:14
  • that question doesn't really answer my question, though, i know what makes slices i was just wandering if a difference exists betwen them – user6774416 Jan 14 '17 at 10:16
  • 1
    While this question might be covered by http://stackoverflow.com/q/509211/674064, it is much more specific than http://stackoverflow.com/q/509211/674064 and has merit of its own. Thus voting for re-opening. – das-g Jan 14 '17 at 10:45
  • From http://stackoverflow.com/a/13005464/674064 I conclude that, no, there probably isn't any difference between `l[:]` and `l[::]`. But I'm not completely sure. – das-g Jan 14 '17 at 10:47

2 Answers2

19

Absolutely no difference between them, at least in Python 3. You can check the byte-code produced for each of these using dis.dis if you'd like:

l = [1, 2, 3, 4]

Byte-code emitted for l[:]:

from dis import dis
dis('l[:]')
  1           0 LOAD_NAME                0 (l)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               0 (None)
              9 BUILD_SLICE              2
             12 BINARY_SUBSCR
             13 RETURN_VALUE

while, byte-code emitted for l[::]:

dis('l[::]')
  1           0 LOAD_NAME                0 (l)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               0 (None)
              9 BUILD_SLICE              2
             12 BINARY_SUBSCR
             13 RETURN_VALUE

as you can see, they're exactly the same. Both load some None's (the two LOAD_CONSTS's) for the values of start and stop used for building the slice (BUILD_SLICE) and apply it. Nones are the default for these as stated in the docs for slices in the Standard Type hierarchy:

Special read-only attributes: start is the lower bound; stop is the upper bound; step is the step value; each is None if omitted. These attributes can have any type.

Use [:], it's less key-strokes.


It's actually interesting to note that in Python 2.x the byte code generated is different and, due to less commands for l[:] it might be slightly more performant:

>>> def foo():
...     l[:]
... 
>>> dis(foo)
  2           0 LOAD_GLOBAL              0 (l)
              3 SLICE+0             
              4 POP_TOP             
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE 

While, for l[::]:

>>> def foo2():
...     l[::]
... 
>>> dis(foo2)
  2           0 LOAD_GLOBAL              0 (l)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               0 (None)
              9 LOAD_CONST               0 (None)
             12 BUILD_SLICE              3
             15 BINARY_SUBSCR       
             16 POP_TOP             
             17 LOAD_CONST               0 (None)
             20 RETURN_VALUE 

Even though I haven't timed these (and I won't, the difference should be tiny) it seems that, due to simply less instructions needed, l[:] might be slightly better.


This similarity doesn't of course exist only for lists; it applies to all Sequences in Python:

# Note: the Bytecode class exists in Py > 3.4
>>> from dis import Bytecode
>>>
>>> Bytecode('(1, 2, 3)[:]').dis() == Bytecode('(1, 2, 3)[::]').dis() 
True
>>> Bytecode('"string"[:]').dis() == Bytecode('"string"[::]').dis() 
True

similarly for others.

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
3

Per the Python language reference section 6.3.2, Subscriptions, the inner expression for a sequence must evaluate to either an integer or a slice. Both these examples produce the same slice, and are therefore identical. There are also numerous other slices that have the same effect, by explicitly stating defaults (start=0, stop=len(sequence) or more, step=1).

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
Yann Vernier
  • 15,414
  • 2
  • 28
  • 26