0

I am trying to clarify my understanding of the differences between these two code snippets which find maximum depth of binary tree. ( for simplicity I didnt inlcude the class )

So the reason the first code variable will always be 1 is becuase its not an object its just a variable, so when I pass it into the functions a new 'version' of it is created.

Whereas in the second code example the function use a refferene to the same array object.

Does this mean python 3 is pass by value for variables and by refference for objects ?

  def maxDepth(self, root: TreeNode) -> int:

        if not root:
            return 0

        max_depth = 1 

        self.check_depth(root.left, max_depth, 1)
        return max_depth

    def check_depth(self, node, max_depth, curr_depth):

        if not node:
            return 

        curr_depth += 1
        self.check_depth(node.left, max_depth, curr_depth)
        self.check_depth(node.right, max_depth, curr_depth)

        max_depth = max(max_depth, curr_depth)
        return

Here the instance variable is replaced by array object.

def maxDepth(self, root: TreeNode) -> int:

    if not root:
        return 0

    max_depth = [1] 

    self.check_depth(root.left, max_depth, 1)
    return max_depth[0]

def check_depth(self, node, max_depth, curr_depth):

    if not node:
        return 

    curr_depth += 1
    self.check_depth(node.left, max_depth, curr_depth)
    self.check_depth(node.right, max_depth, curr_depth)

    max_depth[0] = max(max_depth[0], curr_depth)
    return

Thank you

  • 2
    `1` is an object. **Everything** is an object in Python. Passing an object to a function **never** copies that object. In one case, you mutate the object (your list), in the other, you do not. It is that simple. – juanpa.arrivillaga May 19 '20 at 19:07
  • 1
    Python is always pass-by-reference, but if it's a reference to an immutable object (like an `int`) you can't tell the difference. – Mark Ransom May 19 '20 at 19:08
  • @MarkRansom Python is **never** pass by reference. It is call by object sharing, which is neither call by value nor call by reference. If it *were* call by reference, you could do something like `def foo(&x): x = 42; y = 0; foo(y); print(y)` would `42` but you can't, because Python does not support call by reference semantics at all. It is *closest* to say it is "call by value but everything is an object reference" but that is confusing the *implementation* with the semantics. – juanpa.arrivillaga May 19 '20 at 19:09
  • 1
    @ justanothertechdude "Does this mean python 3 is pass by value for variables and by refference for objects " No, again, **everything** is an object. Python uses *neither of those evaluation strategies*. It uses call by object sharing, sometimes referred to as "call by assignment" because you can think of it as working precisely like assigning to a local variable in your function. See [the accepted answer to this question for more details](https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) – juanpa.arrivillaga May 19 '20 at 19:13
  • @juanpa.arrivillaga thanks for the link, I was thinking of dragging that one out myself. It all depends on your definition of *reference*. I find Python easier to understand by realizing that *everything* is an object, and likewise *everything* is a reference. If you check the CPython implementation you'll find it's literally true, going by the C convention of using pointers for references. – Mark Ransom May 19 '20 at 19:40
  • 1
    @MarkRansom sure, but my point is, call by reference as an evaluation strategy is well defined. People loosely use the term to mean "passing a reference", but that isn't what it actually means. And in any case, in the C implementation, call by value is used, C only supports call by value, and of course, it uses *pointers*. But that doesn't make Python call by value. Let me give you a thought experiment, suppose I implement Python in Fortran, using entirely call by reference. That doesn't make Python call by reference. The semantics of Python's evaluation strategy is different than those two. – juanpa.arrivillaga May 19 '20 at 19:43
  • 1
    Call by reference means that the argument becomes sort of an *alias* for the same variable *in the caller*. So, the classic test is that in a language with call by reference you can implement a `swap` function such that in some other function `a = 1; b = 2; swap(a, b)` will make `a == 2` and `b == 1` *in the caller*. You can't do that in Python. It may seem like a pedantic point... heck, it is a pedantic point... but it's just one of those things that drives me nuts... – juanpa.arrivillaga May 19 '20 at 19:45
  • @juanpa.arrivillaga You mention the list is mutated when passed to a function, but what happens to the variable ? Thanks – justanothertechdude May 20 '20 at 10:06
  • 1
    @justanothertechdude you are using the terminology incorrectly. Everything is an object. On the one hand, you have an `int` object, `max_depth = 1`, on the other hand, you have a `list` object, `max_depth = [1]`. `int` objects *are immutable*, they lack mutator methods. `list` objects are mutable. `max_depth[0] = max(max_depth[0], curr_depth)` is a mutator method, it is list index-assignment. `max_depth = max(max_depth, curr_depth)` simply assigns to a local variable, `max_depth`, and does not mutate the object that was referenced by that variable at all (simple assignment never mutates) – juanpa.arrivillaga May 20 '20 at 10:10
  • 1
    @justanothertechdude read this, it will explain everything: https://nedbatchelder.com/text/names.html – juanpa.arrivillaga May 20 '20 at 10:11
  • 2
    @juanpa.arrivillaga Thank you very much ! I learnt a lot about Python and was able to understand what it is I was doing wrong and why it works the way it does. – justanothertechdude May 20 '20 at 11:34

0 Answers0