C
PY

C to Python

10 lessons

Progress0%
1Variables & Types2Functions3Arrays → Lists4Structs → Classes & Dicts5Memory Management6String Handling7File I/O8Object-Oriented Programming9Exceptions and Context Managers10Standard Library and Tools
All Mirror Courses
C
PY
Exceptions and Context Managers
MirrorLesson 9 of 10
Lesson 9

Exceptions and Context Managers

Python try/except vs C error codes, context managers vs manual cleanup

Introduction

In this lesson, you'll learn about exceptions and context managers in Python. Coming from C, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
C
From C:

In C, you're familiar with python try/except vs c error codes, context managers vs manual cleanup.

PY
In Python:

Python has its own approach to python try/except vs c error codes, context managers vs manual cleanup, which we'll explore step by step.

The Python Way

Let's see how Python handles this concept. Here's a typical example:

PY
Python Example
# Python: exceptions propagate automatically

# try / except / finally
def process_file(path: str) -> str:
    try:
        with open(path, "r") as f:    # with auto-closes on exit
            data = f.read()
        return process(data)
    except FileNotFoundError:
        print(f"File not found: {path}")
        return ""
    except PermissionError as e:
        raise RuntimeError(f"Cannot read {path}") from e

# Custom context manager with __enter__/__exit__
class Timer:
    def __enter__(self):
        import time
        self.start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.elapsed = time.perf_counter() - self.start
        return False  # don't suppress exceptions

with Timer() as t:
    result = expensive_operation()
print(f"Took {t.elapsed:.3f}s")

# contextlib.contextmanager (simpler)
from contextlib import contextmanager

@contextmanager
def managed_resource():
    resource = acquire()
    try:
        yield resource
    finally:
        release(resource)  # always runs

with managed_resource() as r:
    use(r)

Comparing to C

Here's how you might have written similar code in C:

C
C (What you know)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

// C: error codes returned or global errno
int process_file(const char *path) {
    FILE *f = fopen(path, "r");
    if (f == NULL) {
        fprintf(stderr, "fopen: %s\n", strerror(errno));
        return -1;  // error code
    }

    int *buf = malloc(1024);
    if (buf == NULL) {
        fclose(f);  // must remember to clean up!
        return -1;
    }

    // ... process ...
    if (error_condition) {
        free(buf);
        fclose(f);  // easy to forget cleanup
        return -1;
    }

    free(buf);
    fclose(f);
    return 0;  // success
}
Mirror Card
C
From C:

You may be used to different syntax or behavior.

PY
In Python:

Python exceptions propagate automatically — no error code checks needed

Mirror Card
C
From C:

You may be used to different syntax or behavior.

PY
In Python:

with statement auto-calls __exit__ even on exception — replaces C's manual cleanup

Mirror Card
C
From C:

You may be used to different syntax or behavior.

PY
In Python:

FileNotFoundError, PermissionError are descriptive — errno requires strerror()

Mirror Card
C
From C:

You may be used to different syntax or behavior.

PY
In Python:

Custom context managers via __enter__/__exit__ or @contextmanager decorator

Mirror Card
C
From C:

You may be used to different syntax or behavior.

PY
In Python:

No goto needed — finally/with handle cleanup at any exception point

Step-by-Step Breakdown

1. Exception vs Error Code

Python exceptions propagate up the call stack automatically. In C, error codes must be checked and propagated manually at every call site.

C
C
int r = do_thing();
if (r < 0) { cleanup(); return r; }
PY
Python
result = do_thing()  # exception propagates automatically
# cleanup handled by with statement or finally

2. with Statement

The 'with' statement calls __exit__ when the block exits — even if an exception occurs. Replaces C's manual cleanup pattern.

C
C
FILE *f = fopen(...);
if (!f) return -1;
// ... process ...
fclose(f); // must remember!
PY
Python
with open(path, "r") as f:
    data = f.read()
# f.close() called automatically — even on exception

3. Custom Context Managers

Any class with __enter__ and __exit__ works in a 'with' statement. Use @contextmanager for simpler cases.

C
C
// C: wrapper function with init/cleanup
resource_t *acquire();
void release(resource_t *r);
PY
Python
@contextmanager
def db_transaction(conn):
    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise

with db_transaction(conn) as c:
    c.execute("INSERT ...")

4. Exception Hierarchy

Python's exception hierarchy mirrors OS errors. Catch specific types first, then broader types.

C
C
if (errno == ENOENT) { ... }
else if (errno == EACCES) { ... }
PY
Python
try:
    open(path)
except FileNotFoundError: # ENOENT equivalent
    print("not found")
except PermissionError:   # EACCES equivalent
    print("permission denied")
except OSError as e:      # any OS error
    print(f"OS error: {e.strerror}")

Common Mistakes

When coming from C, developers often make these mistakes:

  • Python exceptions propagate automatically — no error code checks needed
  • with statement auto-calls __exit__ even on exception — replaces C's manual cleanup
  • FileNotFoundError, PermissionError are descriptive — errno requires strerror()
Common Pitfall
Don't assume Python works exactly like C. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Exceptions propagate automatically — no error code checks at every call site
  • with statement = auto-cleanup (like try/finally with fclose); works for any context manager
  • FileNotFoundError/PermissionError are descriptive; IOError/OSError for generic OS errors
  • @contextmanager decorator turns a generator into a context manager
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your C code in Python to practice these concepts.
PreviousNext