Variables in C vs Python
In this lesson, you’ll learn the fundamental differences between variables in C and Python. Technically, Python has names rather than variables, but you can still use the term variable. That’s an important distinction when you’re dealing with memory in Python.
00:00
Earlier in this course, you saw how you could declare and initialize an integer variable in C. As I mentioned earlier, three things happen under the hood: C allocates enough memory for an integer, it assigns the value 2337 to that space in memory, and then indicates that x
points to that space in memory. In diagram form, that might look something like this.
00:28 Keep in mind that the actual memory location would normally be a hexadecimal address, much longer than 7f1. What’s interesting about C is that it actually treats the integer as a mutable type.
00:44
This means that we could change the value of x
and it would actually overwrite the previous value without having to create a duplicate integer in memory with the new value.
00:56
This code can be used to create a new integer value y
that contains a copy of whatever is stored in x
. x
is copied by value into y
.
01:08
This means that x
and y
now occupy two entirely different spaces in memory,
01:15 but those different spaces contain the same value. Each value can be modified independently of one another. Moving back over to Python, we see that things work a little differently.
01:29
In fact, Python doesn’t even technically have variables. It has what’s called names. This is a pedantic point, and you should never find yourself in any trouble for calling a Python name “a variable,” but it’s a distinction that’s important to make when dealing with memory in Python. Here’s a line of Python code that assigns the name x
to the value 2337.
01:56
What’s really going on under the hood is a little bit more complex than with C. That’s because the standard interpreter for Python is written in C and so all the Python code we write eventually is represented as if we wrote it in C. First, the CPython interpreter, which is the standard interpreter written in C, will create what’s called a PyObject
in memory.
02:24
The PyObject
is like a container for keys and values, a little bit like a dictionary in Python. The type is set to integer and its value is set to 2337.
02:38
Then, a Python name is created, called x
, and that points to this PyObject
. Because there’s now a name referencing it, the PyObject
’s reference count increases to 1.
02:53
This shows that the Python name x
doesn’t actually own any space in memory with a value. It merely references a space in memory called a PyObject
, and somewhere in that PyObject
is the actual value.
03:10
I should also mention that this PyObject
is different from the Python object type. A PyObject
is the CPython implementation of the Python object that’s actually implemented using a C struct
.
03:25
But because every type in Python inherits from object
, then every type ends up mapping to a PyObject
under the hood, whether it’s a string, an int
, or something like your own type, defined with a class.
03:43
If I try to change the value of x
, which, if you remember, is an immutable integer in Python, then what happens is a whole other PyObject
is created in memory.
03:55
The name changes from referencing the first PyObject
to this new one. The original PyObject
remains in memory, but its reference count is now 0.
04:05
This tells the garbage collector that it can safely free the memory, or in other words, delete the original PyObject
. If this were a mutable type, like a list
, we wouldn’t see this PyObject
duplication happen.
04:21
The value of that PyObject
could be changed directly.
04:26
Let’s try setting a new name, y
, to x
. Instead of the value of x
being copied to a new space in memory for y
,
04:37
like with C, Python simply creates a new name and points it to the same PyObject
04:44
that x
was referencing. As such, its reference count increases to 2. If I said something like y is x
in the interactive shell, it would return True
.
04:56
This is because the is operator checks to see if two names point to the same memory address, or the same PyObject
. The integer type is still immutable, so changing y
would still force Python to create a new PyObject
to point y
to.
05:17
Now, each PyObject
only has one reference. The old PyObject
containing the value 2337 can be freed from memory because no names reference it anymore.
05:33
The big idea is this: in Python, we don’t technically assign variables, even if that’s the terminology we often use. Instead, we bind names to spaces in memory called PyObjects
. Modifying a mutable type will allow the value at that memory space to change, but modifying an immutable type will require a new space in memory, and then the name’s pointer will have to change so that it points to the new PyObject
.
Become a Member to join the conversation.
Jack on Dec. 9, 2020
Finally know how “is” works :)