While we worked with immutables, we passed their values to functions and stored them in variables.
It's different with mutable objects. It's time to learn that everything in Python is passed by reference.
What is a reference? We're going to find out in this lesson. We will start with references' big brothers — addresses and pointers.
References and memory management
The computer's main memory stores all the data needed for a program. To access a specific part of memory, you need to know the address of that part.
In languages with manual memory management, you must constantly monitor that memory at that address is allocated and not yet released. In these languages, the programmer explicitly asks the operating system for the memory needed.
The operating system responds to the request by allocating an area of shared RAM, assigning that block to the requestor, and returning a pointer that is essentially an address. After receiving it, the programmer can store something in the allocated memory.
When we finish the work, we should free the allocated areas. It means we tell the operating system that the memory is free for something else. If the pointer points to a memory area that hasn't been allocated yet or has already been free, the program will end with an error.
Python is a language with automatic memory management. Whenever the programmer needs to create a value, the runtime automatically allocates the required amount of memory. We store the value in this memory and get the reference to the stored value in return results.
Once the data is no longer in use, Python automatically frees the memory. Thus, references play the same role as pointers. But it's always safe to use them because they can't point to an area of memory that's not ready for use.
Also, Python programmers don't have to fetch and fill memory separately because Python places the data in memory at the same runtime.
How references work
When we create a value, we get a reference to it from the runtime.
There can be any number of references to the same value at any time. Python saves work all the time by:
- Passing any value by reference
- Creating new references to existing data
Even variables are just names attached to references. And when you call a function and pass arguments to it, you don't pass the values themselves, only references to them.
When the function ends, Python removes the unnecessary references. Once the last reference to a value disappears, the runtime recognizes it is no longer needed and removes it from memory, freeing the space.
Python does it by a runtime mechanism called a reference counter. Using reference counting allows Python to save a fair amount of memory when passing long strings or large numbers between different parts of the program: you don't have to copy data from place to place, as some other languages do.
But it is a double-edged sword. If we pass a modifiable object reference to some code, we can't prevent that code from modifying the object at runtime. In some cases, this makes the code harder to debug and harder to read. You should always be aware of this feature of Python.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.