Skip to content

Latest commit

 

History

History
92 lines (64 loc) · 2.8 KB

decorators.rst

File metadata and controls

92 lines (64 loc) · 2.8 KB

Decorators

funcy

decorator

Transforms a flat wrapper into a decorator with or without arguments. @decorator passes special call object as a first argument to a wrapper. A resulting decorator will preserve function module, name and docstring. It also adds __wrapped__ attribute referring to wrapped function and __original__ attribute referring to innermost wrapped one.

Here is a simple logging decorator:

@decorator
def log(call):
    print(call._func.__name__, call._args, call._kwargs)
    return call()

call object also supports by name arg introspection and passing additional arguments to decorated function:

@decorator
def with_phone(call):
    # call.request gets actual request value upon function call
    request = call.request
    # ...
    phone = Phone.objects.get(number=request.GET['phone'])
    # phone arg is added to *args passed to decorated function
    return call(phone)

@with_phone
def some_view(request, phone):
    # ... some code using phone
    return # ...

A better practice would be adding keyword argument not positional. This makes such decorators more composable:

@decorator
def with_phone(call):
    # ...
    return call(phone=phone)

@decorator
def with_user(call):
    # ...
    return call(user=user)

@with_phone
@with_user
def some_view(request, phone=None, user=None):
    # ...
    return # ...

If a function wrapped with @decorator has arguments other than call, then decorator with arguments is created:

@decorator
def joining(call, sep):
    return sep.join(call())

Generally a decorator with arguments is required to be called with () when applied to function. However, if you use only keyword only parameters aside from call then you can omit them:

@decorator
def rate_limit(call, *, extra_labels=None):
    # ...

@rate_limit  # no extra labels, parentheses are optional
def func(request, ...):
    # ...

@rate_limit(extra_labels=lambda r: [f"user:{r.user.pk}"])
def func(request, ...):
    # ...

You can see more examples in flow and debug submodules source code.

contextmanager

A decorator helping to create context managers. Resulting functions also behave as decorators. This is a reexport or backport of py3:contextlib.contextmanager.

wraps(wrapped, [assigned], [updated])

unwrap

ContextDecorator