1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
Decorators
==========
.. module:: funcy
.. decorator:: 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 :mod:`flow` and :mod:`debug` submodules source code.
.. decorator:: contextmanager
A decorator helping to create context managers. Resulting functions also
behave as decorators. This is a reexport or backport of :func:`py3:contextlib.contextmanager`.
.. autodecorator:: wraps(wrapped, [assigned], [updated])
.. autofunction:: unwrap
.. autoclass:: ContextDecorator
.. raw:: html
:file: descriptions.html
|