summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2021-04-03 09:54:59 +0200
committerMichele Simionato <michele.simionato@gmail.com>2021-04-03 09:54:59 +0200
commite6e3855c47e3b86054b4640a828b66a837134fc5 (patch)
treef39d89b13645d4d28d835ec4abb36d57e6bf09b0 /docs
parent068743727d9b2f0e9ffb39cc4ebcdf5331a56861 (diff)
downloadpython-decorator-git-e6e3855c47e3b86054b4640a828b66a837134fc5.tar.gz
Documented incompatibility with previous versions
Diffstat (limited to 'docs')
-rw-r--r--docs/documentation.md125
1 files changed, 87 insertions, 38 deletions
diff --git a/docs/documentation.md b/docs/documentation.md
index 95a0903..ecd7a79 100644
--- a/docs/documentation.md
+++ b/docs/documentation.md
@@ -4,7 +4,7 @@ Decorators for Humans
|Author | Michele Simionato|
|---|---|
|E-mail | michele.simionato@gmail.com|
-|Version| 5.0.3 (2021-04-02)|
+|Version| 5.0.3 (2021-04-03)|
|Supports| Python 3.5, 3.6, 3.7, 3.8, 3.9|
|Download page| http://pypi.python.org/pypi/decorator/5.0.3|
|Installation| ``pip install decorator``|
@@ -33,6 +33,8 @@ signature of a decorated function without resorting to "exec" tricks).
The simplification gives a very neat advantage: in case of exceptions
raised in decorated functions the traceback is nicer than it used to be.
That counts as a new feature in my book ;-)
+There is also a change of logic that breaks some decorators, see the section
+about caveats and limitations.
What's New in version 4
-----------------------
@@ -1454,50 +1456,60 @@ not use any cache, whereas the ``singledispatch`` implementation does.
Caveats and limitations
-------------------------------------------
-It should be noted that in Python 3.5, a *lot* of improvements have
-been made: you can decorate a function with
-``func_tools.update_wrapper``, and ``pydoc`` will see the correct
-signature. Unfortunately, the function will still have an incorrect
-signature internally, as you can see by using
-``inspect.getfullargspec``; so, all documentation tools using
-``inspect.getfullargspec`` - which has been rightly deprecated -
-will see the wrong signature.
+Version 5.X breaks compatibility with the past, by making decorators
+more similar to the ones that can be defined with ``functools.wraps``.
+An example will make the issue clear:
-One thing you should be aware of, is the performance penalty of decorators.
-The worse case is shown by the following example:
-
-```bash
- $ cat performance.sh
- python3 -m timeit -s "
- from decorator import decorator
+```python
@decorator
- def do_nothing(func, *args, **kw):
- return func(*args, **kw)
-
- @do_nothing
- def f():
- pass
- " "f()"
+ def chatty(func, *args, **kwargs):
+ print(args, kwargs)
+ return func(*args, **kwargs)
+```
- python3 -m timeit -s "
- def f():
- pass
- " "f()"
+```python
+ @chatty
+ def printsum(x=1, y=2):
+ print(x + y)
```
-On my laptop, using the ``do_nothing`` decorator instead of the
-plain function is five times slower:
-```bash
- $ bash performance.sh
- 1000000 loops, best of 3: 1.39 usec per loop
- 1000000 loops, best of 3: 0.278 usec per loop
+In this example ``x`` and ``y`` are positional arguments with defaults.
+In previous versions of the decorator module
+(< 5) a call to ``printsum()`` would have passed ``args==(1, 2)`` to
+the caller, with an empty ``kwargs`` dictionary. In version 5.X instead
+even ``args`` is empty:
+
+>>> printsum()
+() {}
+3
+
+``args`` become non-empty only if you pass the arguments as positional
+
+>>> printsum(1)
+(1,) {}
+3
+
+and not if you pass them as keyword arguments:
+
+>>> printsum(x=1)
+() {'x': 1}
+3
+
+This can be pretty confusing since non-keyword arguments are passed as
+keywork arguments, but it the way it works with ``functools.wraps`` and
+the way many people expect it to work:
+
+```python
+
+ def chattywrapper(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ print(args, kwargs)
+ return func(*args, **kwargs)
+ return functools.wraps(wrapper)
```
-Of course, a real life function probably does something more useful
-than the function ``f`` here, so the real life performance penalty
-*could* be negligible. As always, the only way to know if there is a
-penalty in your specific use case is to measure it.
In the present implementation, decorators generated by ``decorator``
can only be used on user-defined Python functions, methods or coroutines.
@@ -1556,7 +1568,7 @@ notice that lately I have come to believe that decorating functions with
keyword arguments is not such a good idea, and you may want not to do
that.
-Finally, the implementation is such that the decorated function makes
+The implementation is such that the decorated function makes
a (shallow) copy of the original function dictionary:
```python
@@ -1574,6 +1586,43 @@ a (shallow) copy of the original function dictionary:
```
+Finally, you should be aware of the performance penalty of decorators.
+The worse case is shown by the following example:
+
+```bash
+ $ cat performance.sh
+ python3 -m timeit -s "
+ from decorator import decorator
+
+ @decorator
+ def do_nothing(func, *args, **kw):
+ return func(*args, **kw)
+
+ @do_nothing
+ def f():
+ pass
+ " "f()"
+
+ python3 -m timeit -s "
+ def f():
+ pass
+ " "f()"
+
+```
+On my laptop, using the ``do_nothing`` decorator instead of the
+plain function is five times slower:
+
+```bash
+ $ bash performance.sh
+ 1000000 loops, best of 3: 1.39 usec per loop
+ 1000000 loops, best of 3: 0.278 usec per loop
+```
+
+Of course, a real life function probably does something more useful
+than the function ``f`` here, so the real life performance penalty
+*could* be negligible. As always, the only way to know if there is a
+penalty in your specific use case is to measure it.
+
LICENSE (2-clause BSD)
---------------------------------------------