pythonmemorymemory-managementheap-memorystack-memory

how the local variable are stored and returned in memory (python)?


I always used python without thinking its memory management. But, I have a big question about how it deals memory.

def func1():
    local_var = 1
    print(id(local_var))  # memory address of local_var (stored in stack variable) -> 1
    return local_var


# value copied, and local_var_different_scope points another memory address
local_var_different_scope = func1() 
print(id(local_var_different_scope))  # -> 2
local_var_different_scope = 2
print(id(local_var_different_scope)) # -> 3
  1. I expected that #1 and #2 would print different address, but it was same. Doesn't copying happen in Python when a function returns? If it happens, I think 1 and 2 need to point different address because it is located in different function.
  2. Also, I wondered that 2 and 3 are different. I think if I change the value, then the value in the memory are changed but the address remains the same. For example, below C code shows the same address.
#include <stdio.h>

int main() {
    int a = 1;
    printf("%p\n", &a);
    
    a = 2;
    printf("%p\n", &a); // same as above!

    return 0;
}

I would be really appreciated If you suggest any materials to understand this problem in depth. Thank you!


Solution

  • In Python all assignments are references to objects - in your case integer objects (everything is an object in Python!)

    So in this snippet you've created a 1 (id=xyz) object and returned that object (id=xyz) to local_var_different_scope. So local_var_different_scope now references the id=xyz object (which is the integer 1 you created).

    def func1():
        local_var = 1
        print(id(local_var))  # memory address of local_var (stored in stack variable) -> 1
        return local_var
    

    You then reassigned local_var_different_scope to reference a new integer object 2 (id=abc). Naturally, the id of 2 is different from 1.

    Hope this helps!


    How could an object persist past it's function call?

    Simply put, it persists because the object returned is assigned to a variable, and Python is smart enough to know that!

    Here's another interesting experiment:

    def return_x():
        x = 45
        print(id(x)) # id=123
        return x
    fake_x = return_x()
    print(id(fake_x)) # id=123
    print(x) # NameError 'x' is not defined
    

    One might then guess that since x is returned, it can be referenced - but that is not the case!

    To drive the point home, each assignment is a reference to an object in Python. x simply referenced the object 45 with id=123!

    return x returned the referenced object but not the variable x!