def dispatch(fun, self, *args, **kwargs):
        """calls the decorated function and its hooks"""

        # if object has no hooks, return the original
        if not (_registered_hooks := get_hooks(self)):
            return fun(self, *args, **kwargs)

        function_name = name or fun.__name__

        # function being called not in the list of hooks, return the original
        if not set(_registered_hooks).intersection(
            (f"before_{function_name}", f"after_{function_name}")
        ):
            return fun(self, *args, **kwargs)

        # Create an unhook-able (to avoid recursion)
        # temporary settings to pass to the hooked function
        temp_settings = TempSettingsHolder(self)

        def _hook(action: str, value: HookValue) -> HookValue:
            """executes the hooks for the given action"""
            hooks = _registered_hooks.get(f"{action}_{function_name}", [])
            for hook in hooks:
                value = hook.function(temp_settings, value, *args, **kwargs)
                value = HookValue.new(value)
            return value

        # Value starts as en empty value on the first before hook
        value = _hook("before", HookValue(EMPTY_VALUE))

        # If the value is EagerValue, it means main function should not be
        # executed and the value should go straight to the after hooks if any
        original_value = EMPTY_VALUE
        if not isinstance(value, EagerValue):
            value = MethodValue(fun(self, *args, **kwargs))
            original_value = value.value

        value = _hook("after", value)

        # track the loading history
        # adding inspect history like:
        # "identifier": "get_hook_(read_settings_from_cache_or_db)"
        if value.value != original_value and function_name == "get":
            hook_names = "_".join(
                [
                    hook.function.__name__
                    for list_of_hooks in _registered_hooks.values()
                    for hook in list_of_hooks
                ]
            )
            metadata = SourceMetadata(
                loader="hooking",
                identifier=f"{function_name}_hook_({hook_names})",
                merged=True,
            )
            history = self._loaded_by_loaders.setdefault(metadata, {})
            key = args[0] if args else kwargs.get("key")
            history[key] = value.value

        # unwrap the value from the HookValue so it can be returned
        # normally to the caller
        return value.value
calls the decorated function and its hooks
dynaconf/hooking.py