Python Fundamentals
Data types, control flow, functions, comprehensions, unpacking, generators
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 fallbackReal-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.