1

Background

I'm dealing a bit with recursion lately and I've always been dealing with global vs non global variables and memory stuff. In some of the my latest exercises I've noticed a big difference between lists and ints.

Let's look at the following code:

def foo(x):
    x += 5

def bar(y):
    y.append(2)

def thr(p):
    p[0] += 2


if __name__ == '__main__':
    x = 0
    y = [1]
    p = [3]
    foo(x)
    bar(y)
    thr(p)
    print(x)
    print(y)
    print(p)

output:

0
[1, 2]
[5]

Note how the int hasn't been affected but the list and items inside a list indeed have.

My Question

I know there's a huge difference between a list and an int. and from my experience with other languages (for example c) I can assume that the difference rises because when passing an int it is passed by value and a list is by reference.

Is that correct? why sometimes it seems like lists are passed by value and sometimes by reference (forcing the usage of things like lst.copy()?

Also, I'd like to know how can I pass an int by reference in python (without using something like putting it inside a list as the only element).

snatchysquid
  • 1,283
  • 9
  • 24
  • "I know there's a huge difference between a list and an int. and from my experience with other languages (for example c) I can assume that the difference rises because when passing an int it is passed by value and a list is by reference." No, absolutely incorrect. Python uses **one single** evaluation strategy, which is **neither** call by value nor call by reference. You cannot pass **anything** by reference in Python (not ints or lists), nor by value (although, you can explicitly copy an object) – juanpa.arrivillaga Aug 12 '20 at 19:38
  • 1
    The difference you are seeing here is that in one case, `bar`, your function *mutates the object being passed in*, because you use the mutator method `.append`. In the other case, `foo`, you use `+=`, which for *int* objects **is not a mutator method** (objects define their own behavior for how `+=` works, by implementing the `__iadd__` hook). Indeed, `int` objects *do not expose any mutator methods*, i.e., int objects are immutable. Lists expose many mutator methods. But in either case, the *semantics* of parameter passing is **exactly the same** – juanpa.arrivillaga Aug 12 '20 at 19:40
  • Also, if you are curious, the evaluation strategy python uses is often called different things, although, it was originally seen in CLU and there it was given the name "call by sharing", or "call by object sharing". In any case, [this link](https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/) has a good desription of how this evaluation strategy differs from both call by value and call by reference. Note, *many* modern OOP languages use the same strategy! Javascript, Ruby, Java (except for primitive types) all use this strategy – juanpa.arrivillaga Aug 12 '20 at 19:49
  • Also, you should read this: https://nedbatchelder.com/text/names.html – juanpa.arrivillaga Aug 12 '20 at 19:52
  • Augmented assignment like `+=` is a three step process: Get the object from the variable, perform the operation using methods on the object and get the result, reassign the variable with the result. In that second step, immutable objects create a new object for the result while mutable objects change themselves and use `self` for the result. Some objects get fancy and both mutate and return a different object. When you call `foo(x)` the variable `x` is not rebound, it stays the same, even if the local variable that got reference to x's objecct did. – tdelaney Aug 12 '20 at 20:03

0 Answers0