Skip to content

Instantly share code, notes, and snippets.

@russelldavis
Last active May 2, 2020 22:07
Show Gist options
  • Save russelldavis/69645d00cb8595c2eb94b8b5178e35ef to your computer and use it in GitHub Desktop.
Save russelldavis/69645d00cb8595c2eb94b8b5178e35ef to your computer and use it in GitHub Desktop.
Simplifies creation of decorators
from functools import wraps
def decorator(wrapper):
"""Simplifies creation of decorators.
Removes a layer of nesting (flat is better than nested).
Note that args and kwargs are passed in as simple positional args,
rather than unpacked *args and **kwargs. This avoids potential naming
conflicts between kwargs defined in the wrapped function and the first
arg of the wrapper (usually named "wrapped"). As a side effect, it
discourages unpacking of those args, which decorators generally shouldn't
be doing anyway.
Example:
@decorator
def log_call(wrapped, args, kwargs):
print("entering", wrapped)
return wrapped(*args, **kwargs)
# Instead of:
def log_call(wrapped):
@wraps(wrapped)
def wrapper(*args, **kwargs):
print("entering", wrapped)
return wrapped(*args, **kwargs)
return wrapper
"""
@wraps(wrapper)
def new_decorator(*new_decorator_args):
# new_decorator_args will be [wrapped] for functions,
# or [self, wrapped] for methods.
@wraps(new_decorator_args[-1])
def new_wrapper(*args, **kwargs):
# See docstring for why we don't send args and kwargs unpacked.
# In python >= 3.5, this can be simplified w/ a leading splat.
return wrapper(*(new_decorator_args + (args, kwargs)))
return new_wrapper
return new_decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment