Skip to main content

Data Types

Topic — Python organizes data into four scalar types (holding atomic values: int, float, str, bool) and four collection types (holding multiple elements: list, tuple, dict, set). Understanding the structural properties of each—specifically mutability, ordering, subscript indexing, and hashability—is essential for designing reliable software and efficient data pipelines.


1. The Core Concept​

Every built-in Python data type is governed by three fundamental design questions:

  1. Is it Scalar or Collection? Does it represent a single atomic value (int) or a container of elements (list)?
  2. Is it Mutable or Immutable? Can the object be modified in-place at its existing memory address, or does modification allocate a new object?
  3. Is it Ordered or Unordered? Do elements maintain deterministic sequence positions accessible by index ([0]), or are they hashed sets?

The 8 Foundational Types Overview​

CategoryTypeLiteral ExampleMutabilityOrderingAccess Method
Scalarint28Immutable—Direct scalar
Scalarfloat15.75Immutable—Direct scalar
Scalarstr"Vettri"ImmutableOrderedBy Index (s[0])
ScalarboolTrueImmutable—Logical flag
Collectionlist[1, 2, 3]MutableOrderedBy Index (l[0])
Collectiontuple(1, 2, 3)ImmutableOrderedBy Index (t[0])
Collectiondict{"id": 101}MutableOrdered (Keys unique)By Key (d["id"])
Collectionset{1, 2, 3}MutableUnorderedMembership only (in)
tip

If you only take one thing from this page

  • Use list when you need an ordered sequence that will change.
  • Use tuple when you need an ordered record that must remain protected and hashable.
  • Use dict for lightning-fast key-value lookups.
  • Use set for unique collections and mathematical set operations (union, intersection).

2. Interactive Data Type Taxonomy Explorer​

Filter and inspect the structural metadata, syntax rules, and gotchas across all 8 core types:

Interactive Python Data Type Taxonomy

Click any data type to inspect its structural blueprint and common gotchas:

Sequential Collection
List (list)
Mutable (In-place)Ordered
fruits = ["apple", "banana"]
Access Mechanism:
Zero-based Index (fruits[0])
Uniqueness Rule:
Duplicates allowed
Crucial Gotcha: Lists are unhashable: they cannot be used as dictionary keys or set elements. Assignment (b = a) creates an alias, not a copy!

3. Interactive Mutability & Hashability Sandbox​

Observe what happens when you attempt to modify objects in-place or pass mutable objects as dictionary keys:

In-Place Mutability and Hashability Sandbox

Select an operation scenario to inspect Python runtime memory responses:

✓ In-Place List Mutation (Success)
fruits = ["apple", "banana"]
fruits[0] = "pear"        # In-place index reassignment
fruits.append("grape")    # In-place extension
print(fruits)             # ['pear', 'banana', 'grape']

Mechanism: The list object expands and modifies internal item pointers in-place. The outer memory address (id(fruits)) remains completely unchanged.


4. The Four Collection Types in Detail​


  • Syntax: Square brackets [].
  • Properties: Ordered sequence, supports mixed types, allows duplicates, mutable.
  • Indexing & Slicing:
    nums = [10, 20, 30, 40]
    nums[0] # 10 (First)
    nums[-1] # 40 (Last)
    nums[1:3] # [20, 30] (Stop index excluded)
  • Common Methods: .append(x), .insert(i, x), .pop(), .remove(x).

5. Implementation Lab​

tip

Lab Exercise: Data Types, Collections & Hashability

An interactive, fully functional Google Colab / Jupyter Notebook is available to inspect all 8 types, test in-place mutability, reproduce the shallow tuple trap, and evaluate dictionary key hashability live in your browser.

Open In Colab

How to run the lab:

  1. Click the "Open In Colab" badge above to launch the interactive notebook.
  2. Run cells sequentially to benchmark mutability, hashability errors, and set operations.

Key Experiments to Run:

  • Experiment 1 (In-Place Mutability with id()): Modify a list at index 0 and verify that hex(id(my_list)) remains unchanged before and after mutation.
  • Experiment 2 (The Shallow Tuple Test): Append an integer to a list nested inside a tuple (t[1].append(999)) to witness nested mutation without breaking the outer tuple.
  • Experiment 3 (Testing Key Hashability): Verify that tuples work as dictionary keys (d[(10, 20)]), while lists raise TypeError: unhashable type: 'list'.

6. Common Mistakes​


  • The Misconception: "Parentheses alone create a tuple, so x = (42) is a single-element tuple."
  • Wrong Thinking: Typing x = (42).
  • The Right Principle: Parentheses are also used for arithmetic grouping. Without a trailing comma, (42) is evaluated as integer 42. You must write x = (42,).

7. Summary​

Four Scalar Primitives

  • int: Arbitrary precision. No decimal. Immutable.
  • float: IEEE 754 64-bit float. Approximate decimals. Immutable.
  • str: Immutable text sequence. Slicing returns new strings.
  • bool: Subclass of int. True == 1, False == 0.

Four Collections

  • list []: Ordered, mutable, allows duplicates. Indexing [0].
  • tuple (): Ordered, immutable, hashable. Needs comma (42,).
  • dict {}: Key-value mapping. Keys must be unique and hashable.
  • set {}: Unordered, unique, mutable. Empty set is set().

info

Key Takeaways

  • Mutability dictates safety: Lists and dicts can be modified in-place; tuples and strings cannot.
  • Hashability requires immutability: Only immutable types (integers, strings, tuples) can be used as dictionary keys or set elements.
  • Shallow immutability: A tuple containing a mutable list can have its inner list modified in-place.

Next Section: Expressions and Operators - mastering arithmetic, comparison, logical, and bitwise operators in Python.


8. Active Recall​

Test your understanding by answering first, then clicking to reveal the underlying principles.

Interactive Checkpoint Quiz​

Interactive Checkpoint: The Shallow Tuple Mutation

Consider this Python snippet: t = ("data", [1, 2]); t[1].append(3); print(t). What happens when this code executes?

Review Flashcards​

1. [THEORY] Why can't a list be used as a key in a Python dictionary?

  • The Hashability Invariant: Python dictionaries are hash tables. When a key is inserted, Python computes its hash integer: hash(key).
  • If a key could be mutated in-place (e.g. key.append(5)), its hash integer would change, making the entry impossible to find in its original hash bucket.
  • To prevent silent data corruption, Python enforces that all dictionary keys must be immutable and hashable. Passing a list raises TypeError: unhashable type: 'list'.
2. [MATH] Why does len({1, True, 1.0}) evaluate to 1 instead of 3?

  • Value Equality and Matching Hashes: In Python: 1==True==1.01 == \text{True} == 1.0 hash(1)==hash(True)==hash(1.0)==1\text{hash}(1) == \text{hash}(\text{True}) == \text{hash}(1.0) == 1
  • Because sets strictly eliminate duplicate elements that share both equal value and identical hash values, True and 1.0 are absorbed by the integer 1.
  • The set contains only a single element, so its length is 1.
3. [PRACTICE] What is the difference between dict["key"] and dict.get("key")?

  • dict["key"] attempts direct lookup. If the key is missing, it raises an unhandled KeyError exception.
  • dict.get("key") safely returns None if the key is missing.
  • dict.get("key", default) allows specifying a fallback return value (e.g. d.get("count", 0)), preventing crashes without requiring explicit if key in d: checks.
4. [THEORY] Why is x = (42) an integer, while x = (42,) is a tuple?

  • Grammar Disambiguation: In Python syntax, parentheses () serve dual roles:
    1. Expression grouping: (2 + 3) * 4
    2. Tuple construction: (1, 2)
  • If (42) were parsed as a tuple, mathematical grouping would be impossible.
  • The Python grammar specifies that the comma , is what constructs a tuple, not the parentheses! The trailing comma in (42,) flags it as a tuple.
5. [ANALYZE] How do you create an empty set in Python, and why does {} not work?

  • To create an empty set: Call the constructor function: s = set().
  • Why {} fails: Dictionaries were introduced in Python long before sets were added. Curly braces {} were already reserved to create an empty dictionary (type({}) == dict).
  • Writing {} creates an empty dictionary, not an empty set.