1

I have a method that contains no loops. I pass a list into that method. I assign the list a new value per this snippet:

def do_paging(pageable_list):
    pageable_list = pageable_list[start:end]

In the calling code:

do_paging(source_list)

but it does not look like the source_list gets changed. If I return pageable_list from do_paging() everything is great. Are array arguments immutable?

I started returning the value because it's better. But I am surprised and would like to know what's going on.

EDIT - how could I have been programming Python for a year and not known this!

Tony Ennis
  • 12,000
  • 7
  • 52
  • 73
  • 1
    Arguments in Python are always passed by value. You're just shadowing the argument by defining a new `pageable_list` name. – Vincent Savard Feb 18 '16 at 15:26
  • You aren't modifying the list, you are creating a new list. To modify the list you must modify the list. For example, `pageable_list.append("something")` will modify the list. – Bryan Oakley Feb 18 '16 at 15:27
  • Please read this: http://stackoverflow.com/a/986145/2670792 – Christian Tapia Feb 18 '16 at 15:27
  • 1
    Possible duplicate of [How do I pass a variable by reference?](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) – Christian Tapia Feb 18 '16 at 15:27
  • Also note that modifying a passed mutable is usually a bad idea. Instead, return a new mutable with the changes. – Hugh Bothwell Feb 18 '16 at 15:28

3 Answers3

5

Slicing is creating a new list:

>>> a = [1,2,3]
>>> b = a[1:2]
>>> a is b
False

You are not mutating the original list:

>>> a
[1, 2, 3]

Furthermore, you are never doing anything with the list you assign the name pageable_list to in your do_paging function.

So the problems are a) you don't modify the original list and/or b) you don't return anything from your function. One way to make your code work is to create the slice and reassign the name pageable_list to the return value of your function, i.e.:

def do_paging(pageable_list, start, end):
    return pageable_list[start:end]

pageable_list = do_paging(pageable_list, start, end)

The function should probably take start and end arguments as well, looking for those in the global space is kind of ugly.

However, if all you need your function to do is the slicing, the function is not really useful, you could just use the line

pageable_list = pageable_list[start:end]
timgeb
  • 76,762
  • 20
  • 123
  • 145
3

I noticed this method below when I was recently reviewing code from Quantopian and had never it used before. Per the comment from @Steven_Rumbalski, this is assigning the slice back to the input variable pageable_list.

def do_paging(pageable_list, start, end):
    pageable_list[:] = pageable_list[start:end]

a = [1, 2, 3, 4, 5]

do_paging(a, 2, 4)

>>> a
[3, 4]
Alexander
  • 105,104
  • 32
  • 201
  • 196
  • 2
    The term you are looking for is *slice assignment*. It has nothing to do with pointers and variables. Rather, `pageable_list[:] = pageable_list[start:end]` is syntactic sugar for calling the mutating method `pageable_list.__setslice__`. – Steven Rumbalski Feb 18 '16 at 15:55
  • 1
    Indeed, as `a = 1` and `a[:] = 3` returns the error `TypeError: 'int' object does not support item assignment`. Thanks for the education. – Alexander Feb 18 '16 at 16:16
2

You're not changing "the list". You're assigning a new value to a local variable.

Mutating the list itself would work:

def do_paging(pageable_list):
    pageable_list.pop()

But the variable pageable_list is merely a local variable and assigning some new value to it does not modify the value which was previously assigned to it.

deceze
  • 510,633
  • 85
  • 743
  • 889