🐍 Python Course · Stage 4 · Lesson 67 of 89 · Concept: Objects
Course Overview →

🟩 These concept pages connect Python to programming in general. Read Beginner tab first.

← Concept: Classes Concept: Inheritance →
thecodex.expert · The Codex Family of Knowledge
CS Concepts

Objects

Data grouped by name rather than position — the building block of APIs, configuration, and almost all real-world data.

CS Concepts Language-independent ~18 min read Last verified:
Canonical Definition

An object (in the key-value sense) is a collection of named properties stored in a hash table, providing O(1) average-time lookup, insertion, and deletion by string key rather than integer index.

🟩 Beginner

What an object actually is

What you'll learn: The concept of an object in programming (data + behaviour together). Key-value lookup and why dicts/objects are so fundamental. JSON as the universal object data format.

How to read this tab: This page focuses on objects as a data structure (dict/hash map) as well as OOP objects. Both uses of the word "object" matter in Python.

⏱ 20 min 📄 3 sections 🔶 Prerequisite: Classes
One sentence that captures it

An object is a container that groups related data under named keys — a way to represent a real-world thing and all its properties as one unit.

In Python, everything is an object. Integers are objects. Functions are objects. Classes are objects. Modules are objects. None is an object. This means everything has a type (type(x)), an identity (id(x)), and can have attributes and methods. The practical consequence: you can inspect, modify, and pass anything in Python just like any other value.

What an object is

Where an array uses integer indices (slot 0, slot 1), an object uses string keys. The object {"name":"Priya","age":28,"city":"Mumbai"} groups three values under descriptive names. You access them by name, not by position.

Pythonobjects.py
person = {"name": "Priya", "age": 28, "city": "Mumbai"}

print(person["name"])             # "Priya"
print(person.get("email", "N/A")) # "N/A" — safe with default

person["email"] = "priya@ex.com"  # add
del person["city"]                # remove

for key, value in person.items():
    print(f"{key}: {value}")

print("name" in person)  # True — key membership test
💡

O(1) means constant time regardless of size. A dict with 10 items and a dict with 10 million items both return a value in approximately the same time. This is why dicts are used everywhere for lookup tables, caches, and configuration. The hash function computes an index directly — no searching required.

How key lookup works in O(1)

Objects/dicts use a hash table. The key is passed through a hash function to determine a bucket index. Average lookup, insert, and delete are all O(1) — same speed as array index access, but using string keys.

📎

JSON object maps exactly to Python dict. {"name": "Priya", "age": 30} becomes {"name": "Priya", "age": 30} in Python. This is why JSON and Python play so well together — json.loads() gives you a dict you can use immediately. The main difference: JSON keys must be strings; Python dict keys can be any hashable type.

JSON: objects as data interchange

JSON is the dominant data format on the web — REST APIs, config files, databases. It uses object literal syntax from JavaScript but is language-independent. JSON is supported natively in Python (json module), Java (Gson, Jackson), Go (encoding/json), and every other mainstream language.

Pythonjson_example.py
import json
data = {"product": "Laptop", "price": 85999.0, "in_stock": True}
json_str = json.dumps(data, indent=2)   # serialise
loaded = json.loads(json_str)           # deserialise
print(loaded["product"])                # "Laptop"
📎

The word "object" means slightly different things in different languages. In Python: everything is an object (even integers and functions). In Java: objects are instances of classes; primitives (int, float, boolean) are NOT objects. In JavaScript: objects are key-value maps (like dicts) used for both data and OOP. Knowing this prevents confusion when switching languages.

Objects across languages

Python: dict. JavaScript: Object. Java: HashMap<String, T>. Go: map[string]T. Rust: HashMap<String, T>. Same concept, different syntax and performance characteristics.

✅ Beginner tab complete — check your understanding

  • I can explain what an object is: data (attributes) + behaviour (methods) bundled together
  • I know how key lookup works in a Python dict (O(1) average via hash table)
  • I know JSON object syntax and how it maps to Python dicts

Continue to Inheritance →

🔵 Intermediate

Hash tables: collisions and Python dict internals

What you'll learn: How hash tables achieve O(1) lookup. What hash collisions are and how they're resolved. Python's dict implementation in 3.6+ (compact dict, guaranteed insertion order).

How to read this tab: Understanding hash tables explains why dict lookup is O(1), why dict keys must be hashable, and why you can't use a list as a dict key.

⏱ 20 min 📄 2 sections 🔶 Prerequisite: Beginner tab

Hash collisions are handled, not prevented. Two different keys may hash to the same bucket (a collision). Python's dict uses open addressing: if the target bucket is full, it probes nearby buckets. The load factor (fraction of occupied buckets) determines how often collisions happen. Python resizes the dict when the load factor exceeds ~⅔, keeping lookups fast.

Hash tables: collisions and load factor

A hash table stores entries in an array of buckets. The hash function maps key → bucket index. Collisions occur when two keys map to the same bucket. Python uses open addressing with pseudo-random probing: on collision, probe sequence continues until an empty slot is found. Load factor (entries / capacity) is kept below ~0.67 by resizing and rehashing. A well-loaded Python dict gives average O(1) for all operations; worst-case O(n) occurs only if all keys collide (catastrophically bad hash function).

💡

Python's dict has been redesigned three times for efficiency. Since 3.6 it uses a compact layout that stores keys in insertion order while keeping O(1) lookup. Since 3.7, insertion order is a guaranteed language specification (not just an implementation detail). The 3.6+ dict uses 20-25% less memory than the previous design.

Python dict internals (3.6+)

Python 3.7+ guarantees insertion-order preservation. Internally: a sparse indices array maps hash codes to positions in a compact entries array. This dual-array design has better cache performance than traditional open-addressing tables and uses less memory for typical dict sizes. Documented in CPython source: Objects/dictobject.c.

Commonly confused
A Python dict is not the same as a Python class instance. A dict is a key-value data structure. A class instance has attributes and methods defined by its class. Both use hash tables internally, but {"name":"Priya"} is a dict — not an instance of a Person class.
JSON is not JavaScript. JSON is a language-independent data format inspired by JavaScript object literals. JSON requires double-quoted keys, has no functions/undefined/Date, and is valid in every language.
Python dict keys must be hashable. Integers, strings, and tuples: hashable. Lists and dicts: not hashable (mutable). d[[1,2]] = "val" raises TypeError.
How this connects
Requires first
Confused with

✅ Intermediate tab complete — check your understanding

  • I know how a hash table achieves O(1) lookup (hash the key → find the bucket)
  • I know what a collision is and that Python uses open addressing to handle it
  • I know that Python dicts maintain insertion order since Python 3.7
  • I know only hashable objects can be dict keys (lists cannot; tuples can)

Continue to Inheritance →

🔴 Expert

Hash function contract, hash randomisation, and HashDoS

What you'll learn: The formal contract for hash functions. Python's hash randomisation (PYTHONHASHSEED) and why it was introduced. HashDoS attacks — the security reason Python randomises hash seeds by default.

How to read this tab: Read when working on security-sensitive applications or when you need predictable hash values across Python processes.

⏱ 15 min 📄 2 sections 🔶 Prerequisite: After Stage 2
📎

The hash contract has two rules: 1) Equal objects must have equal hashes (a == b must imply hash(a) == hash(b)). 2) An object's hash must not change during its lifetime. This is why mutable objects (lists) can't be dict keys — their hash would change when mutated. Tuples (immutable) can be keys.

Hash function contract

A valid hash function must: (1) be deterministic; (2) satisfy x == y ⇒ hash(x) == hash(y). The converse (equal hashes imply equal keys) is not required. Python enforces this: defining __eq__ without __hash__ on a class sets __hash__ = None, making instances unhashable.

Hash randomisation and HashDoS

Before Python 3.3, string hashes were deterministic — an attacker could craft inputs that all hash to the same bucket, forcing O(n²) behaviour. Python 3.3 introduced hash randomisation (PEP 456): string hashes are seeded with a random per-process value. Controlled by PYTHONHASHSEED.

Specification reference

PEP 456 — Secure and interchangeable hash algorithm. ECMAScript 2024 §6.1.7 — The Object Type. Python Language Reference §3.3 — __hash__. Java: java.util.HashMap javadoc.

✅ Expert tab complete

  • I know the hash contract: equal objects must have equal hashes
  • I know Python randomises hash seeds by default (PYTHONHASHSEED) to prevent HashDoS attacks
  • I know to set PYTHONHASHSEED=0 when I need reproducible hashes (testing, serialisation)

Continue to Inheritance →

Sources

1
Python Software Foundation. Language Reference §3.3 (__hash__, __eq__). docs.python.org/3/reference/datamodel.html.
2
PEP 456 — Secure hash algorithm. peps.python.org/pep-0456/.
3
ECMAScript 2024 §6.1.7 — The Object Type. Ecma International.
4
Oracle. java.util.HashMap. docs.oracle.com/en/java/docs/api/java.base/java/util/HashMap.html.
Source confidence: High Last verified: Primary source: ECMAScript 2024 §6.1.7 — The Object Type