You can find churned customers with find_first_churned. Now imagine grouping all 500 customers by plan — Starter, Pro, Enterprise — into separate buckets. How does your current workflow handle that?
Pivot table in Excel. Import the Stripe export, pivot by plan, and manually check the groups. It's never clean the first time — there's always some miscategorised row.
A Python dict is your CRM pivot. You iterate the customers, and for each one you append to the list under their plan key. .get() with a default of [] handles plans you haven't seen yet:
groups = {}
for customer in customers:
plan = customer.get("plan", "unknown")
groups[plan] = groups.get(plan, []) + [customer]So a Python dict is literally a customer record? Like one row where you know the column names?
Exactly that. customer = {"name": "Acme Corp", "plan": "pro", "mrr": 149.0} — you ask for customer["plan"] and you get "pro". No VLOOKUP. No column index. Here's the function:
def group_by_plan(customers: list) -> dict:
groups = {}
for customer in customers:
plan = customer.get("plan", "unknown")
if plan not in groups:
groups[plan] = []
groups[plan].append(customer)
print(f"Grouped into {len(groups)} plans")
return groupsWait until we put 500 of them in a dict by plan. That's the whole pivot table replaced.
Wait until we put 500 of them in a list. Which is exactly what filter_active_customers already does.
So filter_active_customers then group_by_plan — that's my Monday pivot table in two function calls.
.items(), .keys(), .values() are your iteration methods on dicts. groups.items() gives you (plan, customers) pairs — useful when you need both the key and the value in a loop.
A dict maps keys to values. Keys can be anything hashable; values can be anything.
d = {"pro": [], "starter": []}
d["pro"].append(customer) # add to existing list
d.get("unknown", []) # default for missing key| Operation | Effect |
|---|---|
d[key] | Get value (raises KeyError if missing) |
d.get(key, default) | Get value or default |
d.keys() | All keys |
d.values() | All values |
d.items() | All (key, value) pairs |
key in d | Check membership |
d[key] crashes on missing keys. d.get(key, default) is always safer for dynamic data.
You can find churned customers with find_first_churned. Now imagine grouping all 500 customers by plan — Starter, Pro, Enterprise — into separate buckets. How does your current workflow handle that?
Pivot table in Excel. Import the Stripe export, pivot by plan, and manually check the groups. It's never clean the first time — there's always some miscategorised row.
A Python dict is your CRM pivot. You iterate the customers, and for each one you append to the list under their plan key. .get() with a default of [] handles plans you haven't seen yet:
groups = {}
for customer in customers:
plan = customer.get("plan", "unknown")
groups[plan] = groups.get(plan, []) + [customer]So a Python dict is literally a customer record? Like one row where you know the column names?
Exactly that. customer = {"name": "Acme Corp", "plan": "pro", "mrr": 149.0} — you ask for customer["plan"] and you get "pro". No VLOOKUP. No column index. Here's the function:
def group_by_plan(customers: list) -> dict:
groups = {}
for customer in customers:
plan = customer.get("plan", "unknown")
if plan not in groups:
groups[plan] = []
groups[plan].append(customer)
print(f"Grouped into {len(groups)} plans")
return groupsWait until we put 500 of them in a dict by plan. That's the whole pivot table replaced.
Wait until we put 500 of them in a list. Which is exactly what filter_active_customers already does.
So filter_active_customers then group_by_plan — that's my Monday pivot table in two function calls.
.items(), .keys(), .values() are your iteration methods on dicts. groups.items() gives you (plan, customers) pairs — useful when you need both the key and the value in a loop.
A dict maps keys to values. Keys can be anything hashable; values can be anything.
d = {"pro": [], "starter": []}
d["pro"].append(customer) # add to existing list
d.get("unknown", []) # default for missing key| Operation | Effect |
|---|---|
d[key] | Get value (raises KeyError if missing) |
d.get(key, default) | Get value or default |
d.keys() | All keys |
d.values() | All values |
d.items() | All (key, value) pairs |
key in d | Check membership |
d[key] crashes on missing keys. d.get(key, default) is always safer for dynamic data.
You have 500 customers and need them grouped by plan for your board deck — Starter, Pro, Enterprise — without opening a pivot table. Write `group_by_plan(customers)` that returns a dict keyed by plan name, where each value is a list of customer dicts on that plan — for example, two customers on 'pro' and one on 'starter' should produce `{'pro': [..., ...], 'starter': [...]}`.
Tap each step for scaffolded hints.
No blank-editor panic.