Reputation: 3081
I have this snippet of code that just sorts a list of numbers that are guaranteed to be between 0 and R-1 (inclusive). The following code does the sort correctly but I don't understand why the input passed in remains unmodified.
def bucket(arr, R):
assert type(arr) is list
for i in arr:
assert i >=0 and i < R
b = [0] * R
for i in arr:
b[i]+=1
arr = []
for ind, v in enumerate(b):
arr = arr + [ind] * v
print(arr)
Why is inp
in this example unchanged after the function has been called:
>>> inp
[3, 1, 4, 5, 4, 5, 5, 5, 1, 5]
>>> bucket(inp, 8)
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]
>>> inp # unchanged, why?
[3, 1, 4, 5, 4, 5, 5, 5, 1, 5]
Upvotes: 2
Views: 1905
Reputation: 13747
Python passes by assignment, and the semantics are extremely similar to Java's pass by value.
The confusion arises because you are passing the pointer by value. This means you cannot modify the pointer inside the function, but no one can stop you from modifying what the pointer is pointing to (i.e. the data) So, for example:
x = 3
def change_x(x):
x = 5
return x
change_x(x)
print x
# Outputs 3
The value of x outside the function (in this case, 3) was copied before x entered the function, so the assignment does nothing. This is typically what we expect when we hear pass by value.
x = [1,2,3]
print(id(x))
# Outputs some "address"
def change_x(x):
x.clear()
x.extend([4,5,6])
print(id(x))
# Outputs the SAME address as above
return x
change_x(x)
print(x)
# Outputs [4,5,6]
What the heck. I thought we just said we couldn't change x. The catch is we didn't change x! We just changed the data x is pointing to (there is a subtle, but important difference here). x is still the same pointer. Note that the addresses output by id
are the same.
x = [1,2,3]
print(id(x))
# Outputs some "address"
def change_x(x):
x = [4,5,6]
print(id(x))
# Outputs some DIFFERENT "address". The pointer to x was changed (inside this function).
return x
change_x(x)
print(x)
# Outputs [1,2,3]
It copied the value of x before it was passed in (the pointer value, not the data, was copied). So, again, reassignment does nothing. Note that the id
function outputs different values this time. So after the function returns, we get the original value of x (the original value of the pointer, that is)
Upvotes: 1
Reputation: 152597
Because you create a new variable called arr
in the line arr = []
and from this point on you operate on a new list. Similarly you always create new lists inside the following for
-loop with the arr = arr + [ind] * v
operations.
You could simply change it to:
def bucket(arr, R):
assert type(arr) is list
for i in arr:
assert i >= 0 and i < R
b = [0] * R
for i in arr:
b[i] += 1
arr[:] = [] # remove all items from the list (in-place)
for ind, v in enumerate(b):
arr.extend([ind] * v) # extend the list in-place, you could also use "arr += [ind] * v"
print(arr)
Example:
>>> inp = [3, 1, 4, 5, 4, 5, 5, 5, 1, 5]
>>> bucket(inp, 8)
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]
>>> inp
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]
Upvotes: 2
Reputation: 733
By assigning []
to arr
you are losing the reference to the existing array, and creating a new one.
To change it, you could use
inp.sort()
Upvotes: 1