Welcome to the beginning of your journey toward Python mastery. This first module lays the groundwork for everything that follows by dissecting the core of Python's design: its object model. Moving from a mid-level to a senior developer requires shifting your perspective from merely using the language to deeply understanding its internal mechanics. This lesson is the first and most critical step in that shift.
Today, we will focus on the single most important principle in Python: everything is an object. We'll deconstruct this idea by examining the three fundamental properties of any Python object: its type, its id, and its value. Mastering this concept is not just academic; it's the key that unlocks a more profound understanding of memory management, argument passing, and performance characteristics—all crucial for building production-grade systems.
The Foundation: Everything is an Object
In many programming languages, a distinction is made between "primitive" data types (like integers or booleans) and "objects." Python eradicates this distinction. An integer, a string, a list, a function, even a module or a class itself—they are all treated uniformly as objects.
This concept can feel abstract, so let's begin with a short, insightful talk by James Powell, a renowned Python expert, who will set the stage for why understanding the object model is so vital.
James Powell: Objectionable Content | PyData Austin 2019
In this video, "Objectionable Content," James Powell introduces the Python object model.
Watch the brief opening segment from 00:41 to 00:52 to understand the focus of our initial lessons: how Python works internally.
This uniform "object" nature means that every piece of data in your program is a self-contained entity with specific attributes and behaviors. The most crucial mental shift is to stop thinking of variables as containers for data. Instead, think of them as labels or names that point to objects residing in memory.
The following animated video provides an excellent visual explanation of this core concept.
How variables work in Python | Explained with Animations [See description/first comment]
This video, "How variables work in Python," uses animations to clarify the relationship between variables and objects.
Watch the section from 00:56 to 01:34. Pay close attention to how creating a variable actually means creating an object in memory and making the variable name refer to it.
Under the Hood: The PyObject
Your goal is to go deep, so let's look at how CPython, the reference implementation of Python, actually represents an object in memory. At the C level, every Python object is built upon a fundamental structure, PyObject. This structure is the common header for all objects.
Let's begin by reading a brief introduction to this foundational structure.
About PyObjects. Delving into Python Objects!
This article, "About PyObjects," delves into the C-level implementation of Python objects.
In the article, read the section titled "PyObject: The Foundation of Everything." Focus on the description that starts here. This will introduce you to the idea that a single C struct underpins all Python objects.
The PyObject structure essentially provides a blueprint. The most crucial fields in its simplified form are a reference count and a pointer to a type object.

This common header is then followed by the specific data, or "value," for that object type. For example, a float object will have the PyObject header followed by a C double to store its value. A complex number object will have the header followed by two C doubles.

This "boxed" nature of Python objects—where even a simple integer is wrapped in this object structure—has significant performance implications, something a senior engineer must always consider. It provides incredible flexibility but comes at the cost of memory overhead and speed compared to "unboxed" machine-level types you might find in languages like C or within specialized libraries like NumPy.
James Powell explains this trade-off clearly.
James Powell: Objectionable Content | PyData Austin 2019
This segment of the "Objectionable Content" talk discusses the performance implications of Python's "boxed" objects.
Watch from 15:20 to 15:54. This connects the abstract object model to real-world performance considerations you'd encounter when designing large-scale systems.
The Object Trilogy: ID, Type, and Value
Now that we have a mental model of an object's structure, let's explore its three defining characteristics from a Python programmer's point of view.
Python's Memory DNA: A Senior Guide to Identity, Interning, and GC
The article "Python’s Memory DNA" provides a concise, senior-level overview of these concepts.
Read the section titled Objects, identity & type. It crisply defines the three pillars of a Python object.
Let's break them down.
-
Identity (
id): This is a unique integer that identifies an object during its lifetime. No two simultaneously existing objects have the same ID. In CPython, this is the object's memory address. You can inspect it using the built-inid()function. The identity is what makes an object distinct, even from other objects that have the same value. -
Type (
type): This defines the object's nature—what kind of data it holds and what operations it supports. It's an object's "class." You can inspect it with the built-intype()function. For example,type(123)returns<class 'int'>, which tells Python that you can perform arithmetic operations on it. -
Value: This is the actual data the object represents. For an integer object, it's the numeric value. For a list object, it's the sequence of items it contains.
Let's see this in action:
# Create a list object with the value [10, 20]
my_list = [10, 20]
# 1. Get its identity
list_id = id(my_list)
print(f"ID: {list_id}")
# 2. Get its type
list_type = type(my_list)
print(f"Type: {list_type}")
# 3. The value is implicitly what my_list represents
print(f"Value: {my_list}")
Practical Application: Identity (is) vs. Equality (==)
The distinction between identity and value is one of the most common sources of bugs for intermediate developers. Understanding it is a hallmark of a senior mindset.
- The
isoperator compares identity.a is bis shorthand forid(a) == id(b). It checks ifaandbare labels pointing to the exact same object in memory. - The
==operator compares value.a == bchecks if the objects thataandbpoint to have equivalent content.
The following video provides a clear, animated distinction.
How variables work in Python | Explained with Animations [See description/first comment]
This part of "How variables work in Python" directly compares the is and == operators.
Watch the segment from 07:11 to 08:09. It visualizes why two lists with the same content are equal in value but not identical.
Let's reinforce this with a classic code example.
a = [1, 2, 3]
b = [1, 2, 3] # A new list object, but with the same value as a
c = a # The label 'c' now points to the *same* object as 'a'
# Comparing values
print(f"a == b: {a == b}") # True, because their contents are the same
print(f"a == c: {a == c}") # True, for the same reason
# Comparing identities
print(f"a is b: {a is b}") # False, because they are two separate objects in memory
print(f"a is c: {a is c}") # True, because both labels point to the same object
print(f"id(a) = {id(a)}")
print(f"id(b) = {id(b)}")
print(f"id(c) = {id(c)}")
This demonstrates that b is an object equal to a, but c is an object that is identical to a. This distinction becomes crucial when we discuss mutable objects in the next lesson.
Solidifying the Mental Model
Finally, let's revisit the concept of variables as labels. Since the type is associated with the object, not the variable, a single variable name can refer to objects of different types throughout its lifetime. This is what makes Python a "dynamically typed" language.
How variables work in Python | Explained with Animations [See description/first comment]
This final clip reinforces the concept of dynamic typing.
Watch from 01:57 to 02:24. It shows how a variable can be "re-labeled" to point to objects of different types.
Consider this code:
x = 100
print(f"x is {x}, type is {type(x)}")
# We are not changing the integer object 100.
# We are making the label 'x' point to a completely new string object.
x = "hello"
print(f"x is {x}, type is {type(x)}")
Key Takeaways
This lesson established the foundational mental model for mastering Python:
- Everything is an object: From numbers to functions, all data is represented by a uniform object structure.
- Variables are labels: Variables don't contain data; they are names that refer to objects in memory.
- The Object Trilogy: Every object has an
id(its unique identity), atype(its behavior and classification), and avalue(the data it represents). - Identity vs. Equality: The
isoperator checks for identical objects (sameid), while the==operator checks for equivalent values.
This framework is the lens through which we will view all subsequent topics.
In our next lesson, we will build directly on this foundation to explore the critical difference between mutable and immutable objects. You'll see how changing an object's value in-place (or not) has profound consequences for how you write correct and efficient code, especially when passing objects to functions.