1. Dynamic Typing vs. Strong Typing
Type Checking at Runtime without Implicit Coercion
- Dynamic typing means variables do not have fixed types; values have types. A variable can hold an int and later hold a str.
- Strong typing means Python will not implicitly cast incompatible types. Adding "5" + 5 raises a TypeError rather than performing string concatenation.
x = 42
print(type(x)) # <class 'int'>
x = "University"
print(type(x)) # <class 'str'>
# print("Score: " + 100) -> Raises TypeError!
💡 Key Takeaway: Dynamic typing allows rapid reassignment, while strong typing prevents subtle silent type coercion bugs.
2. The Taxonomy of Built-in Python Types
Scalars, Sequences, Sets, and Mappings
- Numeric: int (arbitrary precision), float (IEEE 754 double), complex.
- Sequence: list (mutable), tuple (immutable), range (lazy sequence), str (immutable unicode).
- Set: set (mutable, unique), frozenset (immutable, unique).
- Mapping: dict (key-value hash table).
- Boolean & Null: bool (subclass of int), NoneType (singleton None).
types_demo = [
(10, type(10)),
(3.14, type(3.14)),
("text", type("text")),
([1, 2], type([1, 2])),
((1, 2), type((1, 2))),
({"key": "val"}, type({"key": "val"})),
({1, 2}, type({1, 2})),
(None, type(None))
]
for val, t in types_demo:
print(f"{repr(val):<16} -> {t.__name__}")
💡 Key Takeaway: Every built-in type corresponds to a first-class CPython class object.