Skip to content

Instantly share code, notes, and snippets.

@igormolybog
Last active March 13, 2023 19:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save igormolybog/9d3fda894a6c47e1fe428288b8028bda to your computer and use it in GitHub Desktop.
Save igormolybog/9d3fda894a6c47e1fe428288b8028bda to your computer and use it in GitHub Desktop.
Templates for defining python decorators

Templates

Simple decorator

import functools

def decorator(func):
    @functools.wraps(func)      # optional. corrects  __name__ and __doc__ attributes
    def wrapper_decorator(*args, **kwargs):
        # Do something before
        value = func(*args, **kwargs)
        # Do something after
        return value
    return wrapper_decorator

Decorator with optional arguments

Can be called with arguments or as simple decorators

def name(_func=None, *, kw1=val1, kw2=val2, ...): 
    def decorator_name(func):
        ...  # Create and return a wrapper function.

    if _func is None:
        return decorator_name                      
    Else:
        return decorator_name(_func)               

Decorator as a class

import functools

class Decorator:
    def __init__(self, func):
        functools.update_wrapper(self, func)    # optional. corrects  __name__ and __doc__ attributes
        self.func = func

    def __call__(self, *args, **kwargs):
        # Do something before
        value = self.func(*args, **kwargs)
        # Do something after
        return value

Decorator of a class

import functools

def Decorator(cls):
    @functools.wraps(cls)
    def wrapper(*args, **kwargs):
        # Do something before
        instance = cls(*args, **kwargs)
        # Do something after
        return instance
    return wrapper

Examples

Logging

import functools

def debug(func):
    """Print the function signature and return value"""
    @functools.wraps(func)
    def wrapper_debug(*args, **kwargs):
        args_repr = [repr(a) for a in args]                      # 1
        kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]  # 2
        signature = ", ".join(args_repr + kwargs_repr)           # 3
        print(f"Calling {func.__name__}({signature})")
        value = func(*args, **kwargs)
        print(f"{func.__name__!r} returned {value!r}")           # 4
        return value
    return wrapper_debug

Timing

def clock(func):
    def clocked(*args, **kwargs):
        t0 = time.time() # начальное время
        result = func(*args, **kwargs)
        elapsed = time.time() - t0 # конечное время
        arg_1st = []

        if args:
            arg_1st.append(', '.join(repr(arg) for arg in args))
        if kwargs:
            pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
            arg_1st.append(', '.join(pairs))

        arg_str = ', '.join(arg_1st)

        print(f'[{elapsed}s] {func.__name__}({arg_str}) -> {result}')
        return result
    return clocked

Cache

def memoize(f):
    cache = {}

    def decorate(*args):
        if args in cache:
            return cache[args]
        else:
            cache[args] = f(*args)
            return cache[args]
    return decorate

Singleton

import functools

def singleton(cls):
    """Make a class a Singleton class (only one instance)"""
    @functools.wraps(cls)
    def wrapper_singleton(*args, **kwargs):
        if not wrapper_singleton.instance:
            wrapper_singleton.instance = cls(*args, **kwargs)
        return wrapper_singleton.instance
    wrapper_singleton.instance = None
    return wrapper_singleton

Add attribute (units)

def set_unit(unit):
    """Register a unit on a function"""
    def decorator_set_unit(func):
        func.unit = unit
        return func
    return decorator_set_unit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment