DEV Community

DevLog
DevLog

Posted on Originally published at aisideincomelab.blogspot.com

10 Python tricks you'll actually use, 8 of them with zero installs (with the numbers)

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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).
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)