File: decorators.rst

package info (click to toggle)
python-funcy 2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 536 kB
  • sloc: python: 2,989; makefile: 140; javascript: 96; sh: 6
file content (92 lines) | stat: -rw-r--r-- 2,866 bytes parent folder | download | duplicates (2)
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