Python is a dynamically typed, interpreted, high-level language built around readability. Its data model — where everything is an object — combined with first-class functions and generator-based lazy evaluation gives it unusual expressive power. Mastering the fundamentals means understanding not just the syntax but the object model beneath it.

Key Points

  • Everything in Python is an object — integers, functions, classes, modules all have type, id, and value
  • Dynamic typing: variables are labels (references) not boxes — rebinding x = 5 then x = "hello" is fine
  • Mutability: list, dict, set are mutable; int, str, tuple, frozenset are immutable
  • Comprehensions: [expr for item in iterable if cond] — list, dict {k:v ...}, set {x ...}, generator (x ...)
  • Generators: yield turns a function into a lazy iterator — produces values on demand without storing all in memory
  • Unpacking: a, b, *rest = [1,2,3,4,5]; swap a, b = b, a; ** unpacks dicts into kwargs
  • f-strings (Python 3.6+): f"{name!r} is {age} years old" — fastest string interpolation, supports expressions
  • Walrus operator := (Python 3.8): assign and test in one — while chunk := f.read(8192): process(chunk)
  • Truth testing: None, 0, "", [], {}, () are falsy; everything else is truthy — use if lst: not if len(lst) > 0:

Python fundamentals: comprehensions, generators, unpacking, walrus operator, truthiness

# Comprehensions
squares   = [x**2 for x in range(10) if x % 2 == 0]
word_len  = {word: len(word) for word in ["hello", "world"]}
unique_sq = {x**2 for x in range(-5, 6)}
gen       = (x**2 for x in range(10_000_000))  # lazy, no memory spike

# Generator function
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fibs = list(itertools.islice(fibonacci(), 10))  # [0,1,1,2,3,5,8,13,21,34]

# Unpacking
first, *middle, last = range(5)   # first=0, middle=[1,2,3], last=4

def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

config = {"name": "Alice", "greeting": "Hi"}
greet(**config)  # Hi, Alice!

# Walrus operator
import re
if m := re.search(r"\d+", text):  # assign and test
    print(m.group())

# Truthiness in practice
data = []
result = data or "default"  # short-circuit: returns "default"
value = data if data else []  # explicit fallback

Real-World Example

Generators are Python's killer feature for large-scale data processing. A generator pipeline reading a 50GB CSV line by line uses O(1) memory — the same logic with a list comprehension crashes with MemoryError. This pattern powers pandas read_csv(chunksize=...) and SQLAlchemy's yield_per() for streaming large result sets.