Pass by assignment in Python: explain and practice

Intro

Wangyy
3 min readOct 11, 2020

Recently, when I’m practicing on tree problems using python, I found a confusing thing: sometimes the return value isn’t executed as I wanted. Let me give you two problems to specify my confusion.

Problem 1: Given a binary tree, collect a tree’s nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

Example:
Input: {1,2,3,4,5}, Output: [[4, 5, 3], [2], [1]].
Explanation:
1
/ \
2 3
/ \
4 5

The solution to this problem is to print the values of the nodes that share the same depth.

Code:

class Solution:    def findLeaves(self, root):
ans = []
self.depth(root, ans)
return ans
def depth(self, root, ans):
if not root:
return 0
curr = max(self.depth(root.left, ans), self.depth(root.right, ans)) + 1 if len(ans) < curr:
ans.append([])
ans[curr-1].append(root.val)

return curr

Here, I pass ans into the depth function as an argument, after execute the depth function, the ans variable is filled with leaves as we want.

Problem 2: Given a binary tree, find the subtree with maximum sum. Return the root of the subtree.

Example:
Input: {1,-5,2,0,3,-4,-5}, Output:3
Explanation:
The tree is look like this:
1
/ \
-5 2
/ \ / \
0 3 -4 -5
The sum of subtree 3 (only one node) is the maximum. So we return 3.

The solution is to create a helper function to calculate the sum of the current subtree, then update the return value with the node that holds the larger subtree’s sum.

Code:

class Solution:
def findSubtree(self, root):
count = float('-inf')
ans = None
self.subtreeSum(ans, root, count)
return ans

def subtreeSum(self, ans, root, count):
if not root:
return 0

treeSum = root.val + self.subtreeSum(ans, root.left, count) + self.subtreeSum(ans, root.right, count)
if treeSum > count:
count = treeSum
ans = root

return treeSum

However, the return value is None. It seems like after executing the subtreeSum function, it doesn’t change the ans variable.

Why? Why the problem 1 is returning the value as we want, but problem 2 doesn’t? After searching, I found my confusion can be answered by one concept: pass by assignment. But before diving into this concept, let’s learn two major methods of passing arguments into functions: pass by reference and pass by value.

Pass by reference V.S. Pass by value

When calling a function, there are two different ways to pass in arguments: whether to pass by reference or to pass by value. Pass by value is apparently passes the value into the function, which means creating a copy of arguments. After executing the function, the original variables keep untouched. Some programming language like C# and C++, if not specified, it’s default using the pass by value method. On the contrary, pass by reference is not making a copy of the variable, it passes the ‘reference’ which is the address of the variable into a function. So every change made inside the function scope is modifying the original variable.

It still doesn't answer my questions, why Python behaves so differently than other languages? For problem 1, when I pass in a list into a function, it modifies this list in-place, it looks like pass by value. But for problem 2, when I pass in an integer and an object into the function, it doesn’t change at all, it looks like pass by reference. So, what’s the method of passing that Python is using? The answer is: pass by assignment.

Pass by assignment

When calling a function in Python, each function argument becomes a variable to which the passed value is assigned. How Python handles the arguments? It’s depending on the data type of the pass in arguments.

In Python, all data types fall into two categories: mutable and immutable. See the following charts for details:

+-------------+-----------+
| Immutable | Mutable |
+-------------+-----------+
| Integre | List |
| Float | Dictionary|
| Boolean | Set |
| String | Object |
| Tuple | Function |
| Frozenset | |
+-------------+-----------+

If the argument is immutable(e.g. integer, string), when modifying arguments inside the function, Python will create a new location to store the result. However, if the argument is mutable, Python will change it in the original address.

Pass by assignment explains my confusion. For problem 1, the pass-in argument is a list, which is representing the address. Since it’s a mutable data type, any modifying will happens to the original list. For problem 2, we pass an integer to the function, since integer is immutable, any modifying inside the function will make a copy of the original integer.

--

--

Wangyy
Wangyy

Written by Wangyy

on the way to become a programmer

No responses yet