Ten Python tricks, shown live on one machine. Eight ship with Python itself; two are worth a brew install. This is the write-up of the video above: every command, every output, and how each number was measured. Python 3.14.6 throughout.
1. uv: the pip workflow, minus the wait
One Rust binary that stands in for pip and venv, same workflow, familiar commands.
brew install uv
uv venv -p 3.14
UV_NO_CACHE=1 uv pip install requests flask
Three cold installs, pip versus uv, on this machine:
cold install, pip vs uv
package pip uv ratio
requests 0.86s 0.15s 5.7x
flask 0.94s 0.15s 6.4x
pandas 4.07s 0.59s 6.9x
python 3.14.6 both · caches off · 5 runs each, median · alternating order
Conditions: cold installs from PyPI, caches off on both sides, five runs each, median, alternating order so neither tool benefits from going second. The installed artifacts were checked to be identical. uv 0.11.6. For the full setup, existing project and new project, see the uv video and its write-up on this blog.
2. ruff: flake8, black and isort, retired
One tool that lints and formats. Here it cold-scans a frozen snapshot of a real repo, 43 files:
brew install ruff
$ ruff check --no-cache --statistics . | head -12
94 C408 [ ] unnecessary-collection-call
84 SIM115 [ ] open-file-with-context-handler
42 BLE001 [ ] blind-except
25 PLW1510 [ ] subprocess-run-without-check
22 RUF100 [*] unused-noqa
14 I001 [-] unsorted-imports
12 FURB167 [-] regex-flag-alias
12 S110 [ ] try-except-pass
10 F401 [*] unused-import
8 B023 [ ] function-uses-loop-variable
5 EXE001 [ ] shebang-not-executable
5 S112 [ ] try-except-continue
$ ruff check --no-cache . | tail -2
Found 349 errors.
[*] 62 fixable with the `--fix` option (99 hidden fixes can be enabled with the `--unsafe-fixes` option).
349 issues across 43 files in 46 ms, one timed cold run with --no-cache, ruff 0.16.5. [*] marks what --fix will handle for you.
3. f'{x=}': stop typing it twice
Put an equals sign inside the braces and Python prints the variable name and its value together. Built in since 3.8.
>>> x = 42
>>> print(f'{x=}')
x=42
>>> team = 'infra'
>>> print(f'{team=} {x*2=}')
team='infra' x*2=84
Expressions work too, as the second line shows.
4. breakpoint(): a debugger was here all along
Drop it on any line and you are inside a live debugger. No IDE, no setup. Built in since 3.7.
$ cat app.py
def score(user):
base = user["points"] * 2
breakpoint()
return base + bonus(user)
def bonus(user):
return 10 if user["team"] == "infra" else 0
print(score({"name": "mara", "team": "infra", "points": 41}))
$ python3 app.py
> /private/tmp/pydemo/app.py(3)score()
-> breakpoint()
(Pdb) p user
{'name': 'mara', 'team': 'infra', 'points': 41}
(Pdb) p base
82
(Pdb) c
92
p prints, n steps, c continues. Inspect anything, step anywhere.
5. python3 -i: crash autopsy, live
Your script crashed. Run it again with -i and Python drops you at a prompt with the script's variables still loaded.
$ cat crash.py
rows = [line.strip().split(",") for line in open("users.csv")]
header, data = rows[0], rows[1:]
total = sum(int(r[2]) for r in data)
print("total points:", total)
$ python3 -i crash.py
Traceback (most recent call last):
File "/private/tmp/pydemo/crash.py", line 3, in
total = sum(int(r[2]) for r in data)
File "/private/tmp/pydemo/crash.py", line 3, in
total = sum(int(r[2]) for r in data)
ValueError: invalid literal for int() with base 10: 'receipt-7'
>>> data[1]
['jon', 'web', 'receipt-7']
>>> header
['name', 'team', 'points']
The traceback names the value. The prompt shows which row it came from. Do the autopsy right there.
6. http.server: a web server in one line
Zero installs, and the current folder is on your local network. Hand a file to the laptop next to you, then shut it down.
$ python3 -m http.server 8000 2>/dev/null &
[1] 77428
$ curl -sI localhost:8000/orders.json | head -3
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.14.6
Date: Tue, 01 Sep 2026 14:59:55 GMT
$ curl -s localhost:8000/orders.json | head -c 80
{"orders":[{"id":9174,"user":"mara","items":[{"sku":"KB-01","qty":2,"price":39.5
$ kill %1
It serves everything in the directory to anyone on the network. Use it on a network you trust, and kill it when you are done.
7. json.tool: jq, when there's no jq
Any box with Python can pretty-print JSON straight from a pipe.
$ cat orders.json | python3 -m json.tool
{
"orders": [
{
"id": 9174,
"user": "mara",
"items": [
{
"sku": "KB-01",
"qty": 2,
"price": 39.5
},
...
],
"status": "shipped"
},
...
],
"count": 2
}
8. timeit: measure, don't guess
It runs your line enough times to trust the number and reports the best of five. Same line, two sizes; watch the cost move.
$ python3 -m timeit 'sum(range(1000))'
100000 loops, best of 5: 3.7 usec per loop
$ python3 -m timeit 'sum(range(100000))'
500 loops, best of 5: 425 usec per loop
timeit picks the loop count itself, which is why the first line ran 100,000 loops and the second 500. Those are the live runs from the recording.
9. -X importtime: find out where startup goes
Your script feels slow before it even starts? This flag breaks down where that time goes, import by import. Here it is on pandas, output saved with tee so the numbers on screen are the numbers in the file:
$ python -X importtime -c 'import pandas' 2>&1 | tee it.log | tail -6
import time: 386 | 386 | pandas.io.sql
import time: 145 | 145 | pandas.io.xml
import time: 104 | 4290 | pandas.io.api
import time: 73 | 73 | pandas.util._tester
import time: 58 | 58 | pandas._version_meson
import time: 392 | 187650 | pandas
Columns are self time and cumulative time in microseconds. import pandas cost 187,650 µs, about 187 ms, on this run. Sort the log by the second column to find the imports worth deferring.
10. python3 -u: your logs were there all along
Python buffers print output when there is no terminal on the other end, so logs run late and a crash can eat them. -u turns buffering off and every line lands the moment it is written.
$ cat slow_logs.py
import time
for step in ["load config", "connect db", "warm cache", "start worker", "ready"]:
print(f"[boot] {step}")
time.sleep(0.8)
$ python3 slow_logs.py | cat # all five lines appear at once, at the end
$ python3 -u slow_logs.py | cat # one line every 0.8 s, as they happen
The output text is identical; the timing is not. In a container or under a process manager, -u or PYTHONUNBUFFERED=1 is the difference between seeing the last log line before a crash and not.
All ten commands
brew install uv
uv venv -p 3.14
uv pip install requests flask
brew install ruff
ruff check --no-cache .
print(f'{x=}')
breakpoint()
python3 -i app.py
python3 -m http.server 8000
python3 -m json.tool
python3 -m timeit 'sum(range(1000))'
python3 -X importtime app.py
python3 -u app.py
How things were measured, all on a Mac mini M4 Pro with Python 3.14.6: uv versus pip is three packages, cold installs from PyPI, caches off, five runs each, median, alternating order. ruff is one timed cold scan of a frozen snapshot of the repo. importtime is the exact run shown on screen. timeit outputs are the live runs; timeit picks the loop counts and reports the best of five.
Related posts
- Why your Python script is slow: two lines took it 3.71 s to 1.20 s
- Run a Discord bot 24/7 for free on a computer you already own
- npm command not found on Windows: fix the PATH
Originally published at Homelab Notes — notes from one Mac mini running local LLMs and 24/7 automation.
Top comments (0)