This first notebook uses no third-party libraries at all. Everything here is built into Python. Run each cell, read the output, and change a value to see what happens.
import sys; print('Python', sys.version.split()[0], '- no third-party libraries used in this notebook')
Python 3.14.2 - no third-party libraries used in this notebook
DEMO 1 · Values, variables, and types¶
Every value has a type, and the type decides what you can do with it. The four you will meet constantly are int, float, str, and bool. An f-string drops values straight into text.
orders = 3000
revenue = 236108.60
store = "Coffee Corner"
is_open = True
for value in [orders, revenue, store, is_open]:
print(f"{str(value):16} is a {type(value).__name__}")
avg = revenue / orders
print(f"\n{store} took {revenue:,.2f} dollars over {orders:,} orders, averaging {avg:.2f} each.")
3000 is a int 236108.6 is a float Coffee Corner is a str True is a bool Coffee Corner took 236,108.60 dollars over 3,000 orders, averaging 78.70 each.
DEMO 2 · Lists: ordered, changeable collections¶
A list holds items in order. You index from 0, slice with a colon, and negative indices count from the end. Lists have handy methods like append and sort.
regions = ["North", "South", "East", "West"]
print("first:", regions[0], "| last:", regions[-1], "| middle two:", regions[1:3])
regions.append("Central")
regions.sort()
print("sorted, with Central added:", regions)
print("how many regions:", len(regions))
first: North | last: West | middle two: ['South', 'East'] sorted, with Central added: ['Central', 'East', 'North', 'South', 'West'] how many regions: 5
DEMO 3 · Dictionaries, tuples, and sets¶
A dict maps keys to values, the workhorse for labeled data. A tuple is a fixed, unchangeable sequence. A set is an unordered collection of unique items, perfect for de-duplicating.
revenue_by_region = {"North": 56668, "South": 43836, "East": 41704, "West": 55815}
print("North took", revenue_by_region["North"], "dollars")
print("busiest region:", max(revenue_by_region, key=revenue_by_region.get))
point = (40.7, -74.0) # a tuple: cannot be changed
channels = ["web", "web", "mobile", "store", "web", "mobile"]
print("distinct channels:", set(channels)) # a set removes duplicates
North took 56668 dollars
busiest region: North
distinct channels: {'mobile', 'store', 'web'}
DEMO 4 · Control flow and list comprehensions¶
if/elif/else branches, for loops repeat. A list comprehension is Python's compact, readable way to build a new list from an old one, often replacing a whole loop with one line.
prices = [39, 12, 119, 6, 45, 22]
labels = []
for p in prices:
labels.append("premium" if p >= 40 else "standard")
print("with a loop: ", labels)
labels2 = ["premium" if p >= 40 else "standard" for p in prices] # same thing, one line
print("with a comprehension:", labels2)
with_tax = [round(p * 1.08, 2) for p in prices if p >= 20] # transform AND filter
print("prices >= 20, taxed:", with_tax)
with a loop: ['standard', 'standard', 'premium', 'standard', 'premium', 'standard'] with a comprehension: ['standard', 'standard', 'premium', 'standard', 'premium', 'standard'] prices >= 20, taxed: [42.12, 128.52, 48.6, 23.76]
DEMO 5 · Functions: package a calculation once¶
A function names a piece of logic so you can reuse it. Give parameters defaults, return a value, and keep your analysis from turning into copy-paste.
def net_revenue(quantity, price, discount_pct=0):
"""Revenue for a line item after an optional percentage discount."""
return round(quantity * price * (1 - discount_pct / 100), 2)
print("3 x 39, no discount:", net_revenue(3, 39))
print("3 x 39, 10% off: ", net_revenue(3, 39, discount_pct=10))
# a lambda is a tiny anonymous function, handy for sorting
items = [("Mug", 12), ("Grinder", 119), ("Filters", 6)]
print("cheapest first:", sorted(items, key=lambda pair: pair[1]))
3 x 39, no discount: 117.0
3 x 39, 10% off: 105.3
cheapest first: [('Filters', 6), ('Mug', 12), ('Grinder', 119)]
DEMO 6 · A tiny analysis in pure Python (and why we stop here)¶
Using only the standard library, we read the orders file and answer one question: revenue by region. It works, but notice how much bookkeeping it takes. The next four notebooks replace all of it with a line or two of NumPy and pandas.
import csv, tempfile, os
from collections import defaultdict
# For a pure-Python demo we write and read a small CSV (no pandas anywhere in this notebook).
path = os.path.join(tempfile.gettempdir(), "orders_export.csv")
rows = [("North", 120.0), ("South", 80.0), ("North", 60.0), ("West", 200.0), ("South", 40.0)]
with open(path, "w", newline="") as f:
w = csv.writer(f); w.writerow(["region", "revenue"]); w.writerows(rows)
totals = defaultdict(float); counts = defaultdict(int)
with open(path) as f:
for row in csv.DictReader(f):
totals[row["region"]] += float(row["revenue"]); counts[row["region"]] += 1
for region in sorted(totals, key=totals.get, reverse=True):
print(f"{region:8} total {totals[region]:7.2f} over {counts[region]} orders")
print("\nThat is a lot of code for a group-and-sum. In pandas it is one line: df.groupby('region').revenue.sum().")
West total 200.00 over 1 orders
North total 180.00 over 2 orders
South total 120.00 over 2 orders
That is a lot of code for a group-and-sum. In pandas it is one line: df.groupby('region').revenue.sum().
Wrap-up¶
You now have the language itself: types, the four containers (list, dict, tuple, set), control flow, comprehensions, and functions. That is the grammar every library below is written in. The pure-Python group-and-sum in the last cell is the pain that NumPy and pandas exist to remove, which is exactly where we go next.