Zope Hookable
Zope Hookable is a Python package that facilitates the efficient creation of "hookable" objects. These are callable objects designed to be optionally replaced at runtime. This allows developers to define a default behavior for a function and then dynamically change its implementation, affecting all users of that function, even those who imported it. The current version is 8.2 and it is part of the Zope ecosystem, which generally follows semantic versioning with minor releases every 2-6 months and major releases every 2-3 years, though `zope.hookable` itself has a less frequent major release cycle.
Warnings
- breaking Older Python versions are no longer supported. `zope.hookable` has progressively dropped support for EOL Python versions. Version 8.2 requires Python 3.10 or newer. Ensure your environment meets the `requires_python` specification to avoid compatibility errors.
- gotcha `zope.hookable` typically includes a C extension for performance. In environments where C extensions are problematic or for debugging purposes, you can force the use of a pure-Python implementation by setting the `PURE_PYTHON` environment variable to a truthy value before installing or running.
- gotcha Using `zope.hookable` involves modifying global state, as changing a hook's implementation affects all parts of your application that reference that hookable object. This can lead to unexpected side effects or difficult-to-trace bugs if not managed carefully, especially in complex or multi-threaded applications. Ensure proper testing and understand the implications of runtime code replacement.
Install
-
pip install zope-hookable
Imports
- hookable
from zope.hookable import hookable
Quickstart
from zope.hookable import hookable
# 1. Define a default implementation for a function
def _my_default_function(name):
return f"Hello, {name} (default) via id {id(_my_default_function)}"
# 2. Make it hookable
my_hookable_function = hookable(_my_default_function)
# 3. Use the hookable function - it calls the default implementation
print(f"Initial call: {my_hookable_function('World')}")
# 4. Define a new implementation
def _my_custom_function(name):
return f"Greetings, {name} (custom) via id {id(_my_custom_function)}"
# 5. Set the hook to the new implementation
my_hookable_function.sethook(_my_custom_function)
# 6. The function now uses the new implementation
print(f"After hook: {my_hookable_function('User')}")
# 7. Define another implementation
def _my_another_function(name, greeting='Hi'):
return f"{greeting}, {name} (another) via id {id(_my_another_function)}"
# 8. Set another hook, passing additional arguments if necessary for the new hook's signature
my_hookable_function.sethook(_my_another_function, 'Hola')
print(f"Another hook: {my_hookable_function('Friend')}")
# 9. Reset to the original default implementation
my_hookable_function.reset()
print(f"After reset: {my_hookable_function('Again')}")