138. Lists + Sorting + Comprehensions (App V0.2)
RAM Manager v0.2 — threshold alerts and process filtering
138. Lists + Sorting + Comprehensions (App V0.2)
He adds a threshold: if RAM goes above 80%, warn him.
🤔 Socratic question: How does your phone know to send you a “Low Battery” warning? How does AWS know to page an engineer at 3am when a server is dying? Thresholds. This chapter, you build the same thing.
THRESHOLD = 80
def is_ram_critical(percent: float, threshold: int = THRESHOLD) -> bool:
return percent > threshold # alert when ABOVE
stats = get_ram_stats()
if is_ram_critical(stats['percent']):
print(f"⚠️ RAM above {THRESHOLD}%!")He also wants to filter processes: only show the ones using more than 50 MB.
# Keep processes with RSS >= min_mb
filtered = [p for p in processes if p['rss_mb'] >= min_mb]
# Sort descending by RSS
top = sorted(filtered, key=lambda p: p['rss_mb'], reverse=True)[:n]The list comprehension trips him up at first. He writes < min_mb and wonders why it returns tiny processes. The filter keeps things that match the condition — >= min_mb keeps the big ones.
💡 Real-world: Datadog, PagerDuty, and every monitoring tool in existence is built on this exact pattern: collect a metric → compare to threshold → alert. You just built the core of a $10 billion industry in 10 lines of Python.
📺 YouTube search: “how does PagerDuty work” — you’ll recognize everything after this chapter.
💡 Fun fact: Python’s sorted() uses Timsort — a hybrid of merge sort and insertion sort invented by Tim Peters (also the author of “The Zen of Python”). Timsort is so efficient at sorting nearly-sorted data that it was adopted by Java (as Arrays.sort) and Android. Every time you call sorted(), you’re using an algorithm from a Python core developer that is now running on billions of devices.
⚠️ Watch out: The most common list comprehension bug is getting the filter condition backwards. [p for p in procs if p['rss_mb'] >= 50] keeps processes using 50+ MB. [p for p in procs if p['rss_mb'] < 50] keeps tiny processes. Read list comprehensions as: “give me each p from procs if this condition is True.” The condition is the keep condition, not the reject condition.
🤔 Think about it: Why is sorted(filtered, key=lambda p: p['rss_mb'], reverse=True)[:n] better than writing a bubble sort loop yourself? Besides being shorter, what are the performance implications? What happens if filtered has 10,000 processes?
🚨 Aryan adds threshold checking and process filtering to the RAM manager. His threshold comparison uses the wrong operator, the process filter list comprehension has inverted logic, and he loops instead of using sorted() with a key function.
Learning objectives
- Use > operator for threshold comparison (alert when above)
- Filter lists with list comprehensions and >= condition
- Sort dicts by a key with sorted(key=lambda, reverse=True)
- Format output with f-string alignment (< left, > right)
Key concepts
- comparison operators — > < >= <= == !=
- list comprehension — [x for x in lst if condition]
- sorted(key=lambda, reverse=True) — descending sort
- f-string format spec — {value:<width} {value:>width.precision}
Try it
Concept detail
App v0.2 — Threshold alerts and process filtering
Key Python concepts used
# Comparison operators
percent > threshold # True when above (alert condition)
rss_mb >= min_mb # True when at or above minimum
# List comprehension — filter
big_procs = [p for p in all_procs if p['rss_mb'] >= 100]
# sorted() with key function
sorted(procs, key=lambda p: p['rss_mb'], reverse=True)
# f-string alignment
f"{name:<20}" # left-align in 20 chars
f"{pid:>8}" # right-align in 8 chars
f"{mb:>8.0f}" # right-align float, 0 decimal placesWhat v0.2 can do
$ python ram_manager.py
RAM: 72.4% (11.6/16.0 GB)
Process PID RSS MB
--------------------------------------
chrome 812 1800
python 421 670
slack 234 430Solution
import psutil
THRESHOLD = 80
def get_ram_stats() -> dict:
mem = psutil.virtual_memory()
return {
'percent': mem.percent,
'used_gb': mem.used / 1e9,
'total_gb': mem.total / 1e9,
'available_gb': mem.available / 1e9,
}
def is_ram_critical(percent: float, threshold: int = THRESHOLD) -> bool:
return percent > threshold # alert when ABOVE threshold
def get_top_processes(n: int = 5, min_mb: float = 0) -> list[dict]:
processes = []
for proc in psutil.process_iter(['pid', 'name', 'memory_info']):
try:
rss_mb = proc.info['memory_info'].rss / 1e6
processes.append({
'name': proc.info['name'],
'pid': proc.info['pid'],
'rss_mb': rss_mb,
})
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
# Filter: keep processes ABOVE min_mb
filtered = [p for p in processes if p['rss_mb'] >= min_mb]
# Sort descending by rss_mb with sorted() + key
return sorted(filtered, key=lambda p: p['rss_mb'], reverse=True)[:n]
def format_process_table(processes: list[dict]) -> str:
lines = ['Process PID RSS MB']
lines.append('-' * 38)
for p in processes:
lines.append(f"{p['name']:<20} {p['pid']:<8} {p['rss_mb']:>8.0f}")
return '\n'.join(lines)
def main():
stats = get_ram_stats()
print(f"RAM: {stats['percent']:.1f}% ({stats['used_gb']:.1f}/{stats['total_gb']:.1f} GB)")
if is_ram_critical(stats['percent']):
print(f'⚠️ RAM above {THRESHOLD}% — checking top processes')
procs = get_top_processes(n=5, min_mb=10)
print(format_process_table(procs))
if __name__ == '__main__':
main()Tests
from unittest.mock import patch, MagicMock
def _make_proc(name, pid, rss_bytes):
proc = MagicMock()
mem_info = MagicMock()
mem_info.rss = rss_bytes
proc.info = {'name': name, 'pid': pid, 'memory_info': mem_info}
return proc
MOCK_PROCS = [
_make_proc('chrome', 812, 2_000_000_000), # 2000 MB
_make_proc('slack', 234, 400_000_000), # 400 MB
_make_proc('vim', 300, 30_000_000), # 30 MB
]
def test_is_ram_critical_above_threshold():
assert is_ram_critical(85, 80) is True
def test_is_ram_critical_below_threshold():
assert is_ram_critical(75, 80) is False
def test_is_ram_critical_at_threshold():
assert is_ram_critical(80, 80) is False, 'At exactly threshold should not alert'
def test_get_top_processes_filters_min_mb():
with patch('psutil.process_iter', return_value=iter(MOCK_PROCS)):
procs = get_top_processes(n=100, min_mb=50)
for p in procs:
assert p['rss_mb'] >= 50, f"Process {p['name']} below min_mb=50"
# vim at 30 MB should be filtered out
names = [p['name'] for p in procs]
assert 'vim' not in names, 'vim (30 MB) should be filtered out by min_mb=50'
def test_get_top_processes_sorted_descending():
with patch('psutil.process_iter', return_value=iter(MOCK_PROCS)):
procs = get_top_processes(n=10)
rss = [p['rss_mb'] for p in procs]
assert rss == sorted(rss, reverse=True), 'Processes must be sorted descending by RSS'
def test_format_process_table_has_header():
procs = [{'name': 'chrome', 'pid': 812, 'rss_mb': 1800.0}]
table = format_process_table(procs)
assert 'Process' in table
assert 'RSS' in table
def test_format_process_table_includes_process():
procs = [{'name': 'chrome', 'pid': 812, 'rss_mb': 1800.0}]
table = format_process_table(procs)
assert 'chrome' in table
assert '812' in table