Object Model

Back

Loading concept...

🧠 Python Object Model: The Secret Life of Your Data

The Big Idea: Everything is a Box!

Imagine Python as a giant warehouse full of boxes. Every piece of data you create—a number, a word, a list—lives inside a box. Each box has:

  • A label (the variable name)
  • Contents (the actual data)
  • An address (where it lives in memory)

Understanding how Python manages these boxes is the key to writing code that works exactly as you expect!


🏷️ Mutable vs Immutable Objects

The Ice Cream Story

Think of two types of ice cream cones:

Immutable = Frozen Solid Ice Cream 🍦

  • Once made, you can’t change it
  • Want chocolate instead of vanilla? You need a whole new cone!

Mutable = Soft Serve Machine 🍨

  • You can add toppings, mix flavors
  • The same container changes over time

In Python Terms:

Immutable Objects (Cannot change after creation):

# Numbers - frozen solid!
x = 10
x = x + 1  # Creates NEW box with 11
           # Old box (10) still exists

# Strings - also frozen!
name = "cat"
name = name + "s"  # NEW box: "cats"

# Tuples - locked containers
point = (3, 4)
# point[0] = 5  # ERROR! Can't change!

Mutable Objects (Can change in place):

# Lists - flexible containers
basket = ["apple", "banana"]
basket.append("cherry")  # SAME box, new item!
# basket is still the SAME box

# Dictionaries - changeable maps
info = {"name": "Sam"}
info["age"] = 25  # SAME box, new key!

# Sets - modifiable collections
colors = {"red", "blue"}
colors.add("green")  # SAME box!

Why Does This Matter?

# Immutable: Safe to share
a = "hello"
b = a
a = "world"
print(b)  # Still "hello"! Safe!

# Mutable: Sharing has consequences!
list1 = [1, 2, 3]
list2 = list1  # SAME box!
list1.append(4)
print(list2)  # [1, 2, 3, 4] - Surprise!
graph TD A["Create list1 = 1, 2, 3"] --> B["list2 = list1"] B --> C["Both point to SAME box"] C --> D["Change list1"] D --> E["list2 sees changes too!"]

🔍 Object Identity vs Equality

The Twin Paradox

Imagine two kids wearing identical outfits:

  • Equality (==): “Do they look the same?”
  • Identity (is): “Are they the SAME person?”

Python’s Two Questions:

# Same CONTENT (equal)
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)   # True - same stuff inside!
print(a is b)   # False - different boxes!

# Same IDENTITY (same object)
c = [1, 2, 3]
d = c           # d points to SAME box as c
print(c == d)   # True - same content
print(c is d)   # True - SAME box!

The id() Detective Tool:

x = [1, 2, 3]
y = [1, 2, 3]
z = x

print(id(x))  # 140234567890  (address)
print(id(y))  # 140234567999  (different!)
print(id(z))  # 140234567890  (same as x!)

Pro Tip: When to Use Which?

Use == Use is
Comparing values Checking None
Most everyday checks Singleton objects
“Are these equal?” “Same exact object?”
# The RIGHT way to check None
result = some_function()
if result is None:  # Correct!
    print("No result")

# NOT: if result == None (works but wrong style)

🗄️ Memory Management

The Warehouse Manager Story

Python has a super-smart warehouse manager who:

  1. Creates boxes when you need them
  2. Finds storage space automatically
  3. Cleans up boxes nobody uses anymore

How Memory Works:

# Manager creates a box for you
name = "Python"  # Box created, labeled 'name'

# Manager assigns storage address
print(id(name))  # Shows the shelf number!

# Manager tracks who's using each box
a = [1, 2, 3]  # Box created, 1 user
b = a          # Same box, now 2 users!

Python’s Clever Tricks:

Small Integer Caching (Python reuses numbers -5 to 256):

a = 100
b = 100
print(a is b)  # True! Same cached box

x = 1000
y = 1000
print(x is y)  # False! Too big, new boxes

String Interning (Common strings are reused):

s1 = "hello"
s2 = "hello"
print(s1 is s2)  # True! Python is smart

s3 = "hello world!"
s4 = "hello world!"
print(s3 is s4)  # Might be False!
graph TD A["You write: x = 100"] --> B{Is 100 cached?} B -->|Yes| C["Use existing box"] B -->|No| D["Create new box"] C --> E["Assign label 'x'"] D --> E

🗑️ Garbage Collection

The Automatic Janitor

Python has a tireless janitor who:

  • Watches every box in the warehouse
  • Counts how many labels point to each box
  • Throws away boxes nobody uses anymore

Reference Counting in Action:

# Create a box: count = 1
a = [1, 2, 3]

# Another label: count = 2
b = a

# Remove one label: count = 1
del a

# Box still exists because 'b' uses it!
print(b)  # [1, 2, 3] - works!

# Remove last label: count = 0
del b
# Box is garbage collected! Gone!

The Circular Reference Problem:

# Two boxes pointing at each other!
class Node:
    def __init__(self):
        self.friend = None

a = Node()
b = Node()
a.friend = b  # a points to b
b.friend = a  # b points to a

del a, b  # Labels gone, but boxes
          # still point to each other!
          # Reference count never hits 0!

Python’s solution? Generational Garbage Collection:

graph TD A["Generation 0: New objects"] --> B{Survived?} B -->|Yes| C["Move to Generation 1"] B -->|No| D["Collect garbage"] C --> E{Survived again?} E -->|Yes| F["Move to Generation 2"] E -->|No| D F --> G["Long-lived objects"]

Controlling the Janitor:

import gc

# Check garbage collection stats
print(gc.get_count())  # (700, 10, 0)

# Force cleanup now!
gc.collect()

# Turn off automatic collection
gc.disable()

# Turn it back on
gc.enable()

📋 Shallow vs Deep Copy

The Photo Album Analogy

Shallow Copy = Photocopy of your album’s INDEX page

  • You get a new index, but it points to the SAME photos!
  • Change a photo, both albums see it!

Deep Copy = Photocopy of EVERY page

  • Completely independent copies of everything
  • Changes don’t affect each other!

Visual Difference:

original = [[1, 2], [3, 4]]

# SHALLOW: New outer box, same inner boxes
shallow = original.copy()
shallow[0][0] = 999
print(original)  # [[999, 2], [3, 4]] - Changed!

# DEEP: All new boxes!
import copy
deep = copy.deepcopy(original)
deep[0][0] = 888
print(original)  # [[999, 2], [3, 4]] - Unchanged!
graph TD subgraph Original A["Outer List"] --> B["Inner: 1, 2"] A --> C["Inner: 3, 4"] end subgraph Shallow Copy D["NEW Outer"] --> B D --> C end subgraph Deep Copy E["NEW Outer"] --> F["NEW: 1, 2"] E --> G["NEW: 3, 4"] end

Quick Comparison:

Aspect Shallow Copy Deep Copy
Speed Fast ⚡ Slower 🐢
Memory Less More
Independence Partial Complete
Nested objects Shared! Separate

📦 The copy Module

Your Copying Toolkit

import copy

copy.copy() - The Quick Photocopy:

import copy

# Simple objects - works fine
numbers = [1, 2, 3]
copied = copy.copy(numbers)
copied.append(4)
print(numbers)  # [1, 2, 3] - Safe!

# Nested objects - WATCH OUT!
nested = [[1, 2], [3, 4]]
copied = copy.copy(nested)
copied[0][0] = 999
print(nested)  # [[999, 2], [3, 4]] - Oops!

copy.deepcopy() - The Complete Clone:

import copy

# Nested objects - completely safe!
nested = [[1, 2], [3, 4]]
cloned = copy.deepcopy(nested)
cloned[0][0] = 999
print(nested)  # [[1, 2], [3, 4]] - Perfect!

# Works with complex objects too
class Person:
    def __init__(self, name, friends):
        self.name = name
        self.friends = friends

alice = Person("Alice", ["Bob", "Carol"])
alice_clone = copy.deepcopy(alice)
alice_clone.friends.append("Dave")

print(alice.friends)  # ["Bob", "Carol"]
print(alice_clone.friends)  # ["Bob", "Carol", "Dave"]

Other Ways to Copy:

# List shortcuts
original = [1, 2, 3]
copy1 = original[:]      # Slice copy (shallow)
copy2 = list(original)   # Constructor (shallow)
copy3 = original.copy()  # Method (shallow)

# Dictionary shortcuts
data = {"a": 1, "b": 2}
copy1 = data.copy()      # Method (shallow)
copy2 = dict(data)       # Constructor (shallow)

# Set shortcuts
items = {1, 2, 3}
copy1 = items.copy()     # Method (shallow)
copy2 = set(items)       # Constructor (shallow)

Decision Flowchart:

graph TD A["Need to copy something?"] --> B{Simple object?} B -->|Yes| C["Any method works!"] B -->|No| D{Contains nested objects?} D -->|No| E["Use .copy or slice"] D -->|Yes| F{Need independent copy?} F -->|No| G["Shallow copy is fine"] F -->|Yes| H["Use copy.deepcopy"]

🎯 Key Takeaways

  1. Immutable objects (int, str, tuple) create NEW boxes when “changed”
  2. Mutable objects (list, dict, set) modify the SAME box
  3. == checks if values are equal; is checks if same object
  4. Python automatically manages memory with reference counting
  5. Garbage collection cleans up unreachable objects
  6. Shallow copy = new outer container, shared contents
  7. Deep copy = completely independent clone

💡 Quick Reference Card

# Check type mutability
x = [1, 2]  # Mutable
y = (1, 2)  # Immutable

# Identity vs Equality
a == b      # Same value?
a is b      # Same object?
id(a)       # Object's address

# Copying
import copy
copy.copy(obj)      # Shallow
copy.deepcopy(obj)  # Deep

# Garbage Collection
import gc
gc.collect()        # Force cleanup
gc.disable()        # Turn off
gc.enable()         # Turn on

Remember: In Python, understanding the box (object) vs the label (variable) is everything! 📦🏷️

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.