1. Objects in Python
In Python, there is a famous phrase: "Everything is an object." Integers, strings, lists, functions, modules, and custom class instances are all objects under the hood. Understanding how Python handles objects in memory—and how object identity, mutability, and attributes work—is key to writing bug-free, efficient code.
Learning Objectives
- Understand what an object is in memory and why "everything is an object" in Python.
- Master the 3 pillars of any Python object: Identity, Type, and Value (State).
- Differentiate between Value Equality (
==) and Identity Equality (is). - Explore object mutability, pass-by-object-reference behavior, and memory aliasing.
- Inspect object capabilities dynamically using
id(),type(),isinstance(), anddir().
2. What is an Object?
An Object is a container in system memory that holds data (state/attributes) and code (methods/behavior). When you assign a variable in Python, you are not placing data directly inside a box labeled with the variable's name. Instead, Python creates an object in memory and attaches a reference name (the variable) that points to that object's memory address.
Think of an object like a house on a street, and a variable like a sticky note with the house's address written on it. You can stick multiple address notes pointing to the same physical house!
Python code example:
# Standard data types are objects
x = 42 # 'x' references an Integer Object with value 42
msg = "Hello" # 'msg' references a String Object
numbers = [1, 2, 3] # 'numbers' references a List Object
# Checking types using the built-in type() function
print(type(x)) # Output: <class 'int'>
print(type(numbers)) # Output: <class 'list'>
3. The Anatomy of an Object
Every single object created in Python possesses three distinct characteristics:
| Property | What It Represents | How to Inspect It | Can It Change? |
|---|---|---|---|
| Identity | The unique memory address where the object lives. | id(obj) or a is b |
No (Constant for object lifetime) |
| Type | The class blueprint that defines what the object can do. | type(obj) or isinstance() |
No (Cannot change type after creation) |
| Value (State) | The actual data payload held inside the object. | print(obj) or attribute access |
Yes (If object is mutable) |
4. Equality: Value (==) vs Identity (is)
One of the most essential concepts when dealing with objects is distinguishing between checking if two objects hold the same contents versus checking if they are the exact same memory object.
==(Value Equality): Asks "Do these two objects contain equal data?"is(Identity Equality): Asks "Do these two variables point to the exact same physical memory location?" (i.e.,id(a) == id(b)).
Python code example:
list_a = [10, 20, 30]
list_b = [10, 20, 30]
list_c = list_a # Copying reference! Both point to same object
# Comparing Contents (Value Equality)
print(list_a == list_b) # Output: True (Identical numbers inside)
# Comparing Memory Locations (Identity Equality)
print(list_a is list_b) # Output: False (Two separate list objects in RAM!)
print(list_a is list_c) # Output: True (Both point to the exact same memory address!)
# Inspecting actual memory address IDs
print(id(list_a)) # e.g., 1402394820392
print(id(list_b)) # e.g., 1402394820544 (Different ID!)
print(id(list_c)) # e.g., 1402394820392 (Same ID as list_a!)
5. Object Mutability & References
When you pass an object into a function, Python uses a mechanism called Pass-by-Object-Reference. If the object passed is mutable (like a list, dictionary, or custom class instance), modifications made inside a function directly alter the original object outside!
Python code example:
class Player:
def __init__(self, username, score=0):
self.username = username
self.score = score
def award_bonus_points(player_obj, points):
# Mutates the object state directly in memory
player_obj.score += points
p1 = Player("Gamer123", score=100)
award_bonus_points(p1, 50)
# The original object state changed!
print(f"{p1.username} Score: {p1.score}") # Output: Gamer123 Score: 150
6. Dynamic Attribute Inspection & Manipulation
Because Python objects are dynamic, you can inspect their internal methods or dynamically read, set, and delete attributes at runtime using built-in functions:
dir(obj): Returns a list of all attributes and methods available on the object.hasattr(obj, 'attr_name'): Checks if an attribute exists on the object.getattr(obj, 'attr_name', default): Dynamically reads an attribute value.setattr(obj, 'attr_name', value): Dynamically sets or creates a new attribute on an object.
class Car:
def __init__(self, brand):
self.brand = brand
my_car = Car("Toyota")
# Dynamically checking and setting attributes
if hasattr(my_car, "brand"):
print(f"Brand is: {getattr(my_car, 'brand')}")
# Dynamically adding a new attribute to this specific instance!
setattr(my_car, "color", "Red")
print(my_car.color) # Output: Red
7. Common Beginner Mistakes
⚠️ Watch out for these mistakes:
- Using
isfor Value Comparison: Writingif name is "Alice":can cause mysterious bugs because Python may optimize small strings/integers in memory while treating larger ones as separate objects. Always use==for content checks! - Accidental Object Aliasing: Writing
list_b = list_adoes NOT duplicate the list. Modifyinglist_b.append(99)will unintentionally modifylist_aas well! Uselist_b = list_a.copy()instead. - Attempting to Set Attributes on Immutable Built-in Types: Trying to dynamically attach an attribute to built-in immutable types like numbers or strings (e.g.,
x = 5; x.name = "five") raises anAttributeError. - Forgetting that None is an Object: In Python,
Noneis a singleton object of classNoneType. The standard way to check forNoneis using identity equality:if value is None:.
8. Code Examples
Here are essential patterns for inspecting and cloning objects safely in Python:
import copy
# 1. Shallow Copy vs. Deep Copying Objects
original_data = {"user": "Alice", "skills": ["Python", "SQL"]}
# Shallow copy shares nested objects (lists/dicts inside)
shallow_copy = original_data.copy()
# Deep copy duplicates the main object AND all nested objects recursively
deep_copy = copy.deepcopy(original_data)
original_data["skills"].append("Docker")
print(shallow_copy["skills"]) # Output: ['Python', 'SQL', 'Docker'] (Mutated!)
print(deep_copy["skills"]) # Output: ['Python', 'SQL'] (Preserved original!)
# 2. Verifying object types cleanly with isinstance()
def process_data(data_obj):
if isinstance(data_obj, list):
print(f"Processing list of {len(data_obj)} items.")
elif isinstance(data_obj, dict):
print(f"Processing dictionary with keys: {list(data_obj.keys())}")
process_data([1, 2, 3])
process_data({"a": 1, "b": 2})
Mini Practice: Object Inspector
Define a custom class named Gadget with attributes name and price. Create two separate instances with identical values. Print whether their values are equal (==) and whether their memory identities are equal (is).
Practice complete!
Awesome job! You've mastered memory identity and object comparisons in Python.
Test Your Understanding
1. What does the `is` operator evaluate in Python?
2. What function returns the unique integer representing an object's memory address in Python?
3. What happens when you pass a mutable object (like a list or custom object) into a function and modify it inside?
4. Which built-in function allows you to safely check if an object has a specific attribute before accessing it?
9. Challenge Project
Object Memory & Clone Analyzer: Write a Python program that creates a custom BankAccount object with owner and balance attributes. Implement three operations:
- Create an alias reference (
acc_alias = acc1) and modify the balance. Print both variables to observe shared memory! - Use the
copymodule to create a shallow copy, modify the copy's balance, and verify that the original object remains untouched. - Use
id()andisstatements to output a clear memory inspection report comparing all three instances!
10. Key Takeaways
- In Python, everything is an object (integers, strings, lists, functions, classes).
- Every object has three core pillars: an Identity (memory address), a Type, and a Value.
- Use
==to test content equality andisto test memory identity. - Variables store references to objects in memory, not the raw data values themselves.
- Dynamically inspect object capabilities using
id(),isinstance(),dir(), andhasattr().
🚀 Progression
You've mastered Objects and Memory Concepts! Next up, we will explore code reusability and class relationships with **Inheritance & Polymorphism in Python**!