Chasing simple ideas: Everything is an object
Deep dive into Python Objects
Photo by Kelly Sikkema on Unsplash
Simple but not easy: Abstraction
Object-oriented programming cannot be explained without abstraction. Beyond that also It is one of the key principles when building software. While it is important to understand and utilize abstraction, it can get in the way of understanding internals. After all, abstractions are put in place to hide details.
In Python, objects are the abstraction for data. To understand them better, we will have to break through this abstraction layer. Observing the behaviour of Python objects is a good start but we need to dive deeper.
Commonly, these concepts are explained by creating classes for cars, animals, or shapes. Here, we won't do that. Instead, we will use the built-in Python types like int
and list
only.
Code
CPython implementation
We start by taking a look at how CPython implements objects:
typedef struct _object PyObject;
Since AI gets to do the boring work these days, let us ask Cody to explain _object
:
The
_object
struct defines the basic structure of all Python objects. It contains:
_PyObject_HEAD_EXTRA: Extra space for additional fields in debug builds.
ob_refcnt: The reference count field. This is used to track when the object can be deallocated.
ob_type: A pointer to the object's type object. This defines the object's type and its methods.
So in summary,
_object
defines the basic fields that are common to all Python objects - their reference count and type information.More specific object types (like lists, dicts, etc.) build upon this basic _object struct by extending it with additional fields. But they always keep these core fields to maintain memory management and type information.
Adventure with objects
Now, that you have seen the basic structure, let us take help from rich
to see this in action. You can install and import rich as below:
# Install rich with your favourite package manager
# Replace the default print and inspect
from rich import print
from rich import inspect
Notice the 23 attributes that are not shown, use inspect(object, all=True
to see them all. This was still abstract but you get the idea. Now, let us work with actual objects.
Python object has an identity, a type and a value
We can inspect the id, class and value of objects. Here's an example of int
:
Objects have many interesting properties, most importantly:
- 💡An object’s identity never changes once it has been created
Question for beginners: Which one is the object here, x
or 1
? The answer lies in id(x)
which is the memory address.
-
* There are ways to do this assuming you know what you are doing. However, it isn't easy when there are so many ways to shoot yourself in the foot.
-
Notice that
y
is a reference to alist
(a mutabletype
). Objects whose value cannot be changed are called immutable. Understanding this distinction can save you from a lot of trouble. No wonder, mutable arguments made it to the top of common gotchas. Python wouldn't be fun if we couldn't change values. Without mutability, this would be an adventure in functional programming with Lisp or Haskell.
That's a wrap on Python objects. Now you know how to inspect id, type and values. All the code is here as a notebook: