Master Python from the inside out. Here, we don't just write code; we look under the hood at memory management, data types, and logic, all while applying the mindfulness and philosophy of the Bhagavad Gita to our development journey.
⏳ Prerequisite: We have stripped away duplicates with the Yoga of Purity (Sets). Now, we must learn to forge data structures that can never be broken or altered.
Python tuples are the immutable, high-performance counterpart to dynamic lists. In the architecture of code, Lists represent Maya—the illusion of constant change. They grow, shrink, append, and pop. They are chaotic. But not all data is meant to change. Some data is sacred.
When you need to lock application state, secure API responses, or map coordinates, you do not use a List. You use a Tuple.
"The unreal has no existence, and the real never ceases to be." — Bhagavad Gita 2.16
A Tuple is an ordered, immutable collection of elements. Once a Tuple is created in memory, it can never be altered. You cannot append to it. You cannot delete from it. You cannot change an index.
# Forged in parentheses, not brackets
divine_weapons = ("Brahmastra", "Pashupatastra", "Vajra")
# ❌ TRAP: Attempting to mutate throws a TypeError
# divine_weapons[0] = "Sword" -> TypeError: 'tuple' object does not support item assignment
Why intentionally remove features like .append()? Because restricting capabilities breeds performance and safety.
Junior developers use Lists for everything. Senior Architects understand how CPython allocates memory.
Because Lists are dynamic, CPython over-allocates memory. If you create a List of 3 items, CPython reserves space for 4 or 5 items, assuming you will eventually use .append(). This wastes RAM.
Tuples are static. CPython knows exactly how large the Tuple will be the moment it is created. It allocates the exact memory required—not a single byte more. This makes them significantly more memory-efficient and slightly faster to iterate through.
Tuples are not universally faster—they are optimized for stability and memory efficiency, not all operations.
import timeit
list_time = timeit.timeit("['a','b','c']", number=1_000_000)
tuple_time = timeit.timeit("('a','b','c')", number=1_000_000)
print("List: ", list_time)
print("Tuple:", tuple_time)
import sys
list_formation = ["Arjuna", "Bhima", "Karna"]
tuple_formation = ("Arjuna", "Bhima", "Karna")
print(sys.getsizeof(list_formation)) # 88 bytes
print(sys.getsizeof(tuple_formation)) # 64 bytes (27% lighter!)
In languages like Java or C++, returning multiple values from a function requires building complex custom objects. In Python, you just return a Tuple, which can be instantly unpacked. Senior engineers use the _ variable to explicitly discard unused data, signaling intent to the parser.
def fetch_user_data(user_id):
# Fetching from DB...
return "Arjuna", "General", 100
# Elegant Unpacking with Intentional Discard (_)
_, rank, level = fetch_user_data(777)
print(f"Commander is a level {level} {rank}.")
When unpacking a large tuple, you can use the asterisk * to gather remaining items into a list. This is crucial for parsing variable-length data structures.
command_packet = ("EXECUTE", "param_1", "param_2", "param_3")
action, *parameters = command_packet
print(action) # 'EXECUTE'
print(parameters) # ['param_1', 'param_2', 'param_3']
As we learned in Day 5, Dictionary Keys must be hashable. Lists cannot be hashed because they can change. Tuples are locked in time, meaning their hash never changes. This makes them perfect for Compound Keys.
# Mapping a 2D battlefield grid using (X, Y) Tuples as keys
battlefield_grid = {
(0, 0): "Base Camp",
(15, 30): "Enemy Vanguard"
}
print(battlefield_grid[(15, 30)]) # 'Enemy Vanguard'
In high-performance systems, tuples are often used for fixed schemas, coordinates, and cache keys because their immutability guarantees stability and predictable hashing.
Standard tuples have one flaw: you must remember the index (e.g., "Is the email at index 1 or 2?"). To fix this, Python provides the namedtuple.
It acts exactly like a Tuple, but allows you to access elements using dot notation (like an Object), without the massive memory overhead of a full Python class.
from collections import namedtuple
# Define the architecture of the record
WarriorRecord = namedtuple('WarriorRecord', ['name', 'weapon', 'charioteer'])
# Instantiate the record
arjuna = WarriorRecord(name="Arjuna", weapon="Gandiva", charioteer="Krishna")
# Access like an object, perfectly immutable
print(arjuna.weapon) # 'Gandiva'
| Approach | Code | Memory* | Mutable? | Dot access? |
|---|---|---|---|---|
| dict | {"name": "Arjuna", "weapon": "Gandiva"} |
~232 bytes | Yes ⚠ risk | No — d["key"] |
| class | class W: ... |
~400+ bytes | Yes ⚠ risk | Yes ✓ |
| dataclass | @dataclass |
~152 bytes (~56 with slots) |
Optional ✓ safe if frozen | Yes ✓ |
| namedtuple | WRecord("A", "G") |
~64 bytes | No ✓ safe | Yes ✓ |
* Memory sizes are illustrative for a 3-field record on CPython 3.12. Use sys.getsizeof() to measure your own objects.
Python's syntax can be deceptive. Beware these two illusions:
(5) is just an integer surrounded by math brackets. To make a single-element tuple, you must use a trailing comma: (5,).# Trap 2 Demonstration
hybrid_formation = ("Arjuna", ["Sword", "Bow"])
# You cannot do this: hybrid_formation[0] = "Karna"
# But you CAN do this:
hybrid_formation[1].append("Spear")
print(hybrid_formation) # ('Arjuna', ['Sword', 'Bow', 'Spear'])
(5,)Stop reading and start building. Create a financial transaction logger.
log_transaction(user_id, amount).namedtuple called Transaction containing timestamp, user_id, and amount.ledger list.from collections import namedtuple
from datetime import datetime
# 1. Define the immutable record structure
Transaction = namedtuple('Transaction', ['timestamp', 'user_id', 'amount'])
# 2. The master ledger (list of immutable records)
ledger = []
# 3. Your function to implement
def log_transaction(user_id, amount):
# TODO: create a Transaction namedtuple and append to ledger
pass
# 4. Test it
log_transaction("user_007", 500.00)
log_transaction("user_042", 250.00)
# 5. Print the ledger
for tx in ledger:
print(tx)
# 6. Try to alter a past transaction — what happens?
# ledger[0] = ... # This works (list is mutable)
# ledger[0].amount = 999 # This raises: AttributeError
# ✅ Expected output:
# Transaction(timestamp='2026-03-20 10:00:01', user_id='user_007', amount=500.0)
# Transaction(timestamp='2026-03-20 10:00:02', user_id='user_042', amount=250.0)
#
# AttributeError: can't set attribute
Extend this system by:
.append() operations.(item,).Common questions answered — optimised for quick lookup and featured snippets.
.append() calls. In benchmarks, creating a 3-element tuple is roughly 3–5× faster than creating an equivalent list. Iteration speed is similar between the two.
TypeError. However, if a tuple contains a mutable object like a list, that inner object can still be mutated. The tuple locks the reference, not the contents of mutable objects it contains.
namedtuple is a factory function from Python's collections module that creates tuple subclasses with named fields. It behaves exactly like a regular tuple (immutable, memory-efficient) but lets you access elements with dot notation. Use it when you have a fixed record structure and don't need the full overhead of a Python class.
Do not wander the Kurukshetra of code alone. If you are building a legacy, hit the Follow button in the sidebar to receive the remaining days of this 30-Day Series directly to your feed.
Comments
Post a Comment
?: "90px"' frameborder='0' id='comment-editor' name='comment-editor' src='' width='100%'/>