1

When I do something like

for elem in A[a:b]:
  something(elem)

what is happening? Does python make a copy of my array somewhere in memory, or does it just start and end at the selected positions? Is this the same, in terms of memory usage, as using range() as in the following example?

for i in range(a,b):
  something(A[i])
wjandrea
  • 28,235
  • 9
  • 60
  • 81
arthll
  • 27
  • 1
  • 3
  • 1
    slicing a sequence returns a copy of it - in fact, writing `seq[:]` is a quick-and-dirty way of copying a sequence. – jfaccioni Sep 15 '21 at 13:43
  • If `A` is a list then `A[a:b]` is creating a new list containing the specified slice of `A`. It is not the same as using a range. – khelwood Sep 15 '21 at 13:43
  • So it is a better idea to use `range()` in this case ? – arthll Sep 15 '21 at 13:44
  • 1
    @arthll define "better" - processing speed? Memory usage? Code tidyness? – jfaccioni Sep 15 '21 at 13:48
  • What happens when you do a slice is subject of the object you are slicing. Most standard sequence types create a shallow copy, meaning the new sequence is detached from the old sequence but the contained items are references to the same objects as before. – Klaus D. Sep 15 '21 at 14:07
  • 2
    Does this answer your question? [Does a slicing operation give me a deep or shallow copy?](https://stackoverflow.com/questions/19068707/does-a-slicing-operation-give-me-a-deep-or-shallow-copy) TL;DR yes it makes a copy of the list – wjandrea Sep 15 '21 at 14:10
  • Just to make sure, when you say "array", you mean [`list`](https://docs.python.org/3/library/stdtypes.html#lists), right? Arrays are different, like [`array.array`](https://docs.python.org/3/library/array.html) or [NumPy arrays](https://numpy.org/doc/stable/reference/arrays.html). – wjandrea Sep 15 '21 at 14:14
  • @wjandrea I said array thinking about lists and tuples. – arthll Sep 15 '21 at 14:55
  • @wjandrea Regarding the question you suggested. It helped me understand the slicing better, thank you. But when I posted the question I was wondering if placing it in the `for` argument would change anything. But as I understand it, it makes a copy, but it actually points to the address of the items in the original list, so it's not like I'm going to make a completely new list. – arthll Sep 15 '21 at 15:07
  • 1
    @arthll It is a completely new list. Lists don't actually contain their objects, just references to them. And to be clear, the `for` context doesn't change anything. And you're welcome! – wjandrea Sep 15 '21 at 16:11

1 Answers1

2

It depends on the type of the given object you refer to as "array". If you meant the built-in type list -- yes, a copy is made:

>>> a = ['X', 'Y', 'Z']
>>> a
['X', 'Y', 'Z']
>>> b = a[0:2]
>>> b
['X', 'Y']
>>> a[0] = 42  # we modify `a`
>>> a
[42, 'Y', 'Z']
>>> b          # `b` did not change
['X', 'Y']

The same applies to many other sequence types; for example, to bytearray:

>>> ar = bytearray(b'XYZ')
>>> ar
bytearray(b'XYZ')
>>> ar2 = ar[0:2]
>>> ar2
bytearray(b'XY')
>>> ar[0] = 32  # we modify `a`
>>> ar
bytearray(b' YZ')
>>> ar2         # `ar2` did not change
bytearray(b'XY')

But there are types for whom it is not the case; for example:

>>> ar = bytearray(b'XYZ')
>>> view = memoryview(ar)
>>> view
<memory at 0x...>
>>> view.tobytes()
b'XYZ'
>>> view2 = view[0:2]
>>> view2
<memory at 0x...>
>>> view2.tobytes()
b'XY'
>>> view[0] = 32  # this statement modifies both `view` and `view2`, and also `ar`!
>>> view.tobytes()
b' YZ'
>>> view2.tobytes()
b' Y'
>>> ar
bytearray(b' YZ')

Is this the same, in terms of memory usage, as using range() as in the following example?

range() (or, in Python 2, xrange()) is another story, as it does not store its items, but only the range limits (i.e., start and stop) and the optional step:

>>> range(1, 14, 2)  # items 1, 3, 5, 7, 9, 11, 13 are not stored in memory
range(1, 14, 2)
>>> range(1000000000000000000000)  # it does not take zillion bytes of memory :-)
range(0, 1000000000000000000000)
zuo
  • 176
  • 3