Passing by Assignment
In Python, the concept of pass-by-value and pass-by-reference in functions does not exist. Instead, Python implements pass by assignment. This means that neither the values nor the names associated with them are transferred. Rather, every value is associated with the parameter through an assignment.
def find_lowest(numbers):
numbers.sort()
return numbers[0]
nums = [3, 7, 2, 4, 0, 9]
print(nums) # prints [3, 7, 2, 4, 0, 9]
print(find_lowest(nums)) # prints 0
print(nums) # prints [0, 2, 3, 4, 7, 9]
References
In lists and collections, each item is a reference. Similar to how a name is associated with a value, items within collections are associated with values through references. This association is known as reference binding.
Let us look at the references with an example and how it works.
# tic-tac-toe board matrix
board = [["-"] * 3] * 3
for i in board:
print(*i) # prints 3 X 3 matrix with hyphen.
# make an X mark in the center
board[1][1] = "X"
for i in board:
print(*i)
#Above print prints the below
# - X -
# - X -
# - X -
In the above code the default expectation is to change only the index [1][1] to "X" but, all the rows with index 1 become "X". This is because all three lists are aliases for a single list. To get the normally expected tic-tac-toe board where every list is not aliased below list comprehension can be used.
board = [["-"] * 3 for _ in range(3)]
When the value of any index is changed in the board, it does not affect other values as in the previous example.
Shallow copy and Deep copy
A shallow copy creates a new object and copies the references to the original object's elements. It means that if the original object contains mutable objects, both the original and the copied objects will refer to the same mutable objects in memory.
A deep copy creates a new object and recursively copies the contents of the original object and all of its nested objects. In other words, a deep copy creates a new copy of the objects within the original object.
# shallow copy
original_list = [1, 2, [3, 4]]
new_list = list(original_list)
new_list[2].append(5)
print(original_list) # prints [1, 2, [3, 4, 5]]
print(new_list) # prints [1, 2, [3, 4, 5]]
# deep copy
original_list = [1, 2, [3, 4]]
new_list = copy.deepcopy(original_list)
new_list[2].append(5)
print(original_list) # prints [1, 2, [3, 4]]
print(new_list) # prints [1, 2, [3, 4, 5]]
Copying is the most common way to solve the problem of passing around mutable objects in python in functions. Using id to check if the values have been modified does not work in python as shown below example.
a = [1, 2, 3]
b = [4, 5, 6]
c = (a, b)
print(id(c)) # prints id of tuple c
a.append(0)
print(c) # prints ([1, 2, 3, 0], [4, 5, 6])
print(id(c))# prints the same id as before for c as c has only reference of a and b as its value.
Top comments (0)