diff --git a/content/blog/python-refactoring-exceptions-context-manager.md b/content/blog/python-refactoring-exceptions-context-manager.md new file mode 100644 index 0000000..75d8bfd --- /dev/null +++ b/content/blog/python-refactoring-exceptions-context-manager.md @@ -0,0 +1,88 @@ +--- +title: "Quick Python: Refactoring Exceptions with Context Manager" +date: 2024-02-01T20:48:21-05:00 +draft: false +tags: ["Python"] +math: false +medium_enabled: false +--- + +I generally find exception syntax a little clunky... + +```python +try: + for _ in range(5): + sleep(1) +except KeyboardInterrupt: + # Awesome task 1 + # Awesome task 2... + pass +``` + +Especially if you end up capturing the same exceptions and handling it the same way. + +```python +try: + for _ in range(5): + sleep(1) +except KeyboardInterrupt: + # Awesome task 1 + # Awesome task 2... + pass + +try: + for _ in range(2): + sleep(1) +except KeyboardInterrupt: + # Awesome task 1 + # Awesome task 2... + pass +``` + +One way to make our code more DRY (don't-repeat-yourself) is to make use of Python's context managers. + +```python +@contextmanager +def handle_sigint(): + try: + yield + except KeyboardInterrupt: + # Awesome task 1 + # Awesome task 2... + pass +``` + +Using the context manager, everything within the indented block gets executed within the try block. + +```python +with handle_sigint(): + for _ in range(5): + sleep(1) + +with handle_sigint(): + for _ in range(2): + sleep(1) +``` + +In fact, we can write this in a generic way to give us an alternative syntax for handling exceptions. + +```python +@contextmanager +def handle_exception(f, *exceptions): + try: + yield + except exceptions as e: + f(e) +``` + +For example, let's tell the user that we're explicitly ignoring their exception + +```python +def ignore(e): + print("Ignoring", e.__class__.__name__) + +with handle_exception(ignore, NotImplementedError, KeyboardInterrupt): + for _ in range(5): + sleep(1) +``` +