A few days ago, if someone asked me how to augment the method of a given class in Python, I would suggest creating a new class that inherits from the parent class, and then overriding that method. In the case of a function, I would propose to decorate it.
Decoration would also work for methods, but since OOP offers out-of-the-box functionality (method override) for this very situation, it seems more natural to stick with this functionality.
Today my answer would be different since I wrote a new iteration (which I find satisfying after several attempts) of a Python library I built to implement hooking [1] in my projects.
This library exposes a decorator [2] to tag methods and functions (targets), and so when they are called, user-defined hooks will be executed upstream or downstream according to the spec (Before vs After) provided by the user.
Arguments to targets are passed to hooks which can modify them or replace the targets themselves with an arbitrary callable [3] or None [4].
Thanks to the tagging mechanism, hooks are not directly tied to targets but to tags (either user-defined or derived from functions or methods themselves). Thus, hooks are loosely coupled to targets and dynamically bound to tags.
The library, minimalist and intuitive, is written in Python and is available on PyPI [5]. I would like to know what you think about it. Your questions and comments are welcome.
[1] https://en.wikipedia.org/wiki/Hooking
[2] https://peps.python.org/pep-0318/
[3] https://en.wikipedia.org/wiki/Callable_object