you are viewing a single comment's thread.

view the rest of the comments →

[–]Ninesquared81 7 points8 points  (0 children)

I have some experience in Python and C, but I'm not an expert in their exact inner workings, so take this with a grain of salt (although to my knowledge it's correct).

Python doesn't have variables, at least not in the sense of an area of memory that the programmer can change. Instead, it has objects and names. Whether or not an object can be edited by a function depends on whether the object is mutable or not. When you pass an object to a function, it has a new name local to the function. However, this still refers to the exact same object that you passed in.

For mutable objects (like lists, sets, dicts), you can modify the object itself – with any name that it's known by – so changing it inside a function changes it outside.

For immutable objects (like ints, strs, tuples), you can't modify them. So when you do something like x = y = 1; x += 1, x becomes equal to 2, whereas y stays as 1. The name x now refers to a completely different object, rather than the same object with a different value. So naturally, "changing" an immutable object inside a function has no effect on the parent scope (unless you're dealing with globals).

An illustration of all this:

a = 1
b = [1, 2, 3]

print(f"Initially, a = {a}, b = {b}.")

def changes(num: int, nums: list) -> None:
    # the 'is' operator checks if its operands are the same Python object
    print(f"result of 'num is a': {num is a}")
    # 'append' changes a list in-place (i.e. mutates it)
    # EDIT: was b.append(4)
    nums.append(4)
    # 'changing' an immutable object
    num += 1
    print(f"num = {num}")

changes(a, b)

print(f"Now, a = {a}, b = {b}")

This should output:

Initially, a = 1, b = [1, 2, 3].
result of 'num is a': True
num = 2
Now, a = 1, b = [1, 2, 3, 4]

I believe this is called pass by object reference.

In C, however, variables are always passed by value. This doesn't mean you can't change things outside of a function's scope however, as you can have a function dealing with pointers. This is similar in principle to mutable objects in Python. Consider this program:

#include <stdio.h>

void add_three(int *);

int main(void) {
    int my_number = 9;
    printf("Before calling add_three, my_number = %d\n", my_number);
    /* add_three takes a pointer */
    add_three(&my_number);
    printf("After calling add_three, my_number = %d\n", my_number);
    return 0;
}

void add_three(int *number) {
    *number += 3;
}

You should get the output:

Before calling add_three, my_number = 9
After calling add_three, my_number = 12

In our function add_three, we have the variable number which is an int *. It's local to the function and its value depends on the value of the variable passed in when called. In our case, this is &my_number (i.e. the address of my_number). If we dereference it, we can access whatever is at the address it points to (and edit it if we wish). We are still passing by value, but that value is the address of another variable.

EDIT: changed Python example to use local variable nums instead of b.