What I Took From Finishing Python Crash Course

After finishing Python Crash Course—venv, safe dict access, and writing your own context manager.

I’ve been shipping code in JavaScript, TypeScript, and Go for years. Python was the gap. I went through Python Crash Course by Eric Matthes from start to finish, and it’s one of the best resources I’ve used to go from zero to “I can build and ship Python.” Clear structure, no fluff, and exercises that force you to type code instead of skim. Once you finish it, you have enough to write scripts, small tools, and read production Python with confidence.

Here’s what the book gives you by the end, one thing it doesn’t emphasize enough (virtual environments), and something a bit more advanced: writing your own context manager so you can use with for your own resources.


After finishing the book

By the time you finish Python Crash Course, you’ve got variables, strings, numbers, lists, conditionals, loops, dictionaries, user input, while, functions, classes, files, and at least one project (game, data viz, or web app). You get f-strings, list comprehensions, .get() and .items(), and the habit of “run it, break it, fix it.” The exercises are the right mix of guided and open-ended. Doing every one is what makes it stick.

One pattern that pays off everywhere: safe dict access. In real code you often don’t know if a key exists. Using dict.get(key, default) instead of dict[key] avoids KeyError. Wrapping that in a small helper for nested keys keeps scripts from blowing up on missing data—more on that below.


What you need in the real world: virtual environments

The book gets you writing Python; it doesn’t spend much time on where you run it. In practice, you never install packages globally. You use an isolated environment per project. That’s what venv (built into Python) is for.

Why venv matters

  • Dependencies: Project A needs requests==2.28, project B needs 2.31. One global install can’t satisfy both.
  • Reproducibility: pip freeze > requirements.txt and pip install -r requirements.txt so you and others can recreate the same environment.
  • No pollution: Your system Python stays clean; no sudo pip install or permission mess.

Quick loop

python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# ... work ...
pip freeze > requirements.txt
deactivate

Create → activate → install → freeze when deps change → deactivate. Once that’s muscle memory, you’re set.


Safe nested access: a small helper

Here’s a minimal pattern for reading nested dict keys (e.g. from JSON or API responses) without crashing on missing keys:

import json

def get_nested(data: dict, *keys, default=None):
    """Get a nested key without KeyError. Example: get_nested(d, 'user', 'address', 'city')"""
    for key in keys:
        if not isinstance(data, dict):
            return default
        data = data.get(key)
        if data is None:
            return default
    return data

with open("config.json") as f:
    config = json.load(f)

city = get_nested(config, "user", "address", "city", default="unknown")
print(f"City: {city}")

data.get(key) returns None or your default if the key is missing. Chaining that in a loop gives you safe deep access. Type hint data: dict helps when the script grows.


Super technical: writing your own context manager

The book shows with open(...) as f. You use with so the file is closed even if an exception happens. That’s a context manager. Once you know how they work, you can write your own for any “setup → use → teardown” pattern: locks, timers, temporary state, API sessions, etc.

Python gives you two ways to implement one.

1. Class-based: __enter__ and __exit__

Any class that defines __enter__ and __exit__ can be used with with:

import time

class Timer:
    """Context manager that prints how long the block took."""
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        elapsed = time.perf_counter() - self.start
        print(f"Elapsed: {elapsed:.3f}s")
        return False  # don't suppress exceptions

# Usage
with Timer():
    time.sleep(0.1)
# Elapsed: 0.100s
  • __enter__ runs when you enter the with block; its return value is what you get after as (e.g. with Timer() as t:).
  • __exit__ runs when you leave the block (normally or by exception). The three arguments are the exception type, value, and traceback; if you return True, Python swallows the exception. Returning False (or nothing) re-raises it.
  • Here we only use it to measure time and print; we don’t suppress errors.

2. Generator-based: @contextmanager

For simple cases, a generator plus contextlib.contextmanager is less boilerplate:

from contextlib import contextmanager

@contextmanager
def temporary_override(obj, attr, value):
    """Temporarily override an attribute; restore it when leaving the block."""
    old = getattr(obj, attr, None)
    setattr(obj, attr, value)
    try:
        yield
    finally:
        if old is not None:
            setattr(obj, attr, old)
        else:
            delattr(obj, attr)

# Example: temporarily change a config
class Config:
    debug = False

with temporary_override(Config, "debug", True):
    print(Config.debug)  # True
print(Config.debug)  # False again
  • Everything before yield is “setup”; everything after (in the finally) is “teardown”.
  • The finally ensures teardown runs even if the block raises. That’s what makes context managers safe.
  • This pattern shows up everywhere: mocking in tests, changing env vars, acquiring and releasing locks.

Why this is worth knowing

Once you can write a context manager, you stop repeating try/finally by hand for the same resource. You get one place that owns “open/close” or “acquire/release,” and callers just write with MyResource():. It’s the same idea as with open(...) but for your own abstractions. The book doesn’t go deep here; learning it yourself is a solid next step after finishing the last chapter.


What’s next

After finishing Python Crash Course you have enough to write CLI tools, automate tasks, and read other people’s Python. Adopt venv and safe dict access early; add context managers when you start building things that manage resources (files, connections, locks). If you’re going through the book or coming from another language, those three will make your code feel more professional and less “tutorial-only.”