summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2015-07-24 10:10:13 +0200
committerMichele Simionato <michele.simionato@gmail.com>2015-07-24 10:10:13 +0200
commit753173a95aaf26837b3ede284f007fa3b591c598 (patch)
tree736a7b97ec4bc7b932bfc3469edbea4088007b78 /src
parent55f28695e817fd7eac8870330843b3dff8f49eaa (diff)
downloadpython-decorator-git-753173a95aaf26837b3ede284f007fa3b591c598.tar.gz
Improvements to the docs
Diffstat (limited to 'src')
-rw-r--r--src/tests/documentation.py97
1 files changed, 54 insertions, 43 deletions
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index 04ee70e..e82ba8e 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -19,7 +19,7 @@ Introduction
The decorator module is over ten years old, but still alive and
kicking. It is used by several frameworks (IPython, scipy, authkit,
-pylons, repoze, pycuda, sugar, ...) and has been stable for a *long*
+pylons, pycuda, sugar, ...) and has been stable for a *long*
time. It is your best option if you want to preserve the signature of
decorated functions in a consistent way across Python
releases. Version 4.0 is fully compatible with the past, except for
@@ -29,7 +29,7 @@ decision made it possible to use a single code base both for Python
2,000 lines of duplicated documentation/doctests. Having to maintain
separate docs for Python 2 and Python 3 effectively stopped any
development on the module for several years. Moreover, it is now
-trivial to distribute the module as a wheel_ since 2to3 is no more
+trivial to distribute the module as an universal wheel_ since 2to3 is no more
required. Since Python 2.5 has been released 9 years ago, I felt that
it was reasonable to drop the support for it. If you need to support
ancient versions of Python, stick with the decorator module version
@@ -44,8 +44,8 @@ What's new
Since now there is a single manual for all Python versions, I took the
occasion for overhauling the documentation. Therefore, even if you are
an old time user, you may want to read the docs again, since several
-examples have been improved. The packaging has been improved and now I
-am also distributing the code in wheel format. The integration with
+examples have been improved. The packaging has been improved and I
+am distributing the code in wheel format too. The integration with
setuptools has been improved and now you can use ``python setup.py
test`` to run the tests. A new utility function ``decorate(func,
caller)`` has been added, doing the same job that in the past was done
@@ -56,14 +56,15 @@ anymore.
Apart from that, there is a new experimental feature. The decorator
module now includes an implementation of generic (multiple dispatch)
functions. The API is designed to mimic the one of
-`functools.singledispatch` but the implementation is much simpler;
-moreover all the decorators involved preserve the signature of the
-decorated functions. For the moment the facility is there mostly to
-exemplify the power of the module. In the future it could change
-and/or be enhanced/optimized; on the other hand, it could even become
-deprecated. Such is the fate of experimental features. In any case it
-is very short and compact, so you can extract it for your own
-use. Take it as food for thought.
+``functools.singledispatch`` (introduced in Python 3.4) but the
+implementation is much simpler; moreover all the decorators involved
+preserve the signature of the decorated functions. For the moment the
+facility is there mostly to exemplify the power of the module. In the
+future it could be enhanced/optimized; on the other hand, both its
+behavior and its API could change. Such is the fate of experimental
+features. In any case it is very short and compact (less then one
+hundred lines) so you can extract it for your own use. Take it as food
+for thought.
Usefulness of decorators
------------------------------------------------
@@ -135,14 +136,18 @@ the result of the function call in a dictionary, so that the next time
the function is called with the same input parameters the result is retrieved
from the cache and not recomputed. There are many implementations of
``memoize`` in http://www.python.org/moin/PythonDecoratorLibrary,
-but they do not preserve the signature.
+but they do not preserve the signature. In recent versions of
+Python you can find a sophisticated ``lru_cache`` decorator
+in the standard library (in ``functools``). Here I am just
+interested in giving an example.
+
A simple implementation could be the following (notice
that in general it is impossible to memoize correctly something
that depends on non-hashable arguments):
$$memoize_uw
-Here we used the functools.update_wrapper_ utility, which has
+Here i used the functools.update_wrapper_ utility, which has
been added in Python 2.5 expressly to simplify the definition of decorators
(in older versions of Python you need to copy the function attributes
``__name__``, ``__doc__``, ``__module__`` and ``__dict__``
@@ -166,16 +171,16 @@ keyword arguments:
.. code-block:: python
- >>> from decorator import getargspec
+ >>> from decorator import getargspec # akin to inspect.getargspec
>>> print(getargspec(f1))
ArgSpec(args=[], varargs='args', varkw='kw', defaults=None)
-This means that introspection tools such as *pydoc* will give
-wrong informations about the signature of ``f1``, unless you are
-using a recent of Python 3.X. This is pretty bad:
-*pydoc* will tell you that the function accepts a generic signature
-``*args``, ``**kw``, but when you try to call the function with more than an
-argument, you will get an error:
+This means that introspection tools such as ``pydoc`` will give wrong
+informations about the signature of ``f1``, unless you are using
+Python 3.5. This is pretty bad: ``pydoc`` will tell you that the
+function accepts a generic signature ``*args``, ``**kw``, but when you
+try to call the function with more than an argument, you will get an
+error:
.. code-block:: python
@@ -184,8 +189,8 @@ argument, you will get an error:
...
TypeError: f1() takes exactly 1 positional argument (2 given)
-Notice even in Python 3.5 `inspect.getargspec` and
-`inspect.getfullargspec` (which are deprecated in that release) will
+Notice even in Python 3.5 ``inspect.getargspec`` and
+``inspect.getfullargspec`` (which are deprecated in that release) will
give the wrong signature.
@@ -404,9 +409,9 @@ the final result. Here is a minimalistic example of usage:
... time.sleep(.5)
... return x
- >>> f1 = long_running(1)
- >>> f2 = long_running(2)
- >>> f1.result() + f2.result()
+ >>> fut1 = long_running(1)
+ >>> fut2 = long_running(2)
+ >>> fut1.result() + fut2.result()
3
contextmanager
@@ -556,7 +561,7 @@ Getting the source code
Internally ``FunctionMaker.create`` uses ``exec`` to generate the
decorated function. Therefore
``inspect.getsource`` will not work for decorated functions. That
-means that the usual '??' trick in IPython will give you the (right on
+means that the usual ``??`` trick in IPython will give you the (right on
the spot) message ``Dynamically generated function. No source code
available``. In the past I have considered this acceptable, since
``inspect.getsource`` does not really work even with regular
@@ -577,7 +582,7 @@ $$example
(see bug report 1764286_ for an explanation of what is happening).
Unfortunately the bug is still there, in all versions of Python except
Python 3.5, which is not yet released. There is however a
-workaround. The decorated function has an attribute ``.__wrapped__``,
+workaround. The decorated function has an attribute ``__wrapped__``,
pointing to the original function. The easy way to get the source code
is to call ``inspect.getsource`` on the undecorated function:
@@ -769,6 +774,14 @@ calling ``.dispatch_info(*types)``:
>>> win.dispatch_info(StrongRock, Scissors)
[('StrongRock', 'Scissors'), ('Rock', 'Scissors')]
+Since there is no direct implementation for (StrongRock, Scissors)
+the dispatcher will look at the implementation for (Rock, Scissors)
+which is available. Internally the algorithm is doing a cross
+product of the class precedence lists (or Method Resolution Orders,
+MRO_ for short) of StrongRock and Scissors respectively.
+
+.. _MRO: http://www.python.org/2.3/mro.html
+
Generic functions and virtual ancestors
-------------------------------------------------
@@ -786,7 +799,7 @@ considered to be a subclass of the abstract base class ``collections.Sized``:
>>> issubclass(WithLength, collections.Sized)
True
-However, ``collections.Sized`` is not in the MRO of ``WithLength``, it
+However, ``collections.Sized`` is not in the MRO_ of ``WithLength``, it
is not a true ancestor. Any implementation of generic functions, even
with single dispatch, must go through some contorsion to take into
account the virtual ancestors.
@@ -892,7 +905,7 @@ head by looking at the implementations. I will just notice that
[('V',), ('Sized',), ('S',), ('Container',)]
The current implementation does not implement any kind of cooperation
-between generic functions, i.e. there is nothing akin to call-next-method
+between implementations, i.e. there is nothing akin to call-next-method
in Lisp, nor akin to ``super`` in Python.
Finally, let me notice that the decorator module implementation does
@@ -971,19 +984,17 @@ the decorated function is called.
At present, there is no clean way to avoid ``exec``. A clean solution
would require to change the CPython implementation of functions and
add an hook to make it possible to change their signature directly.
-That could happen in future versions of Python (see PEP 362_) and
-then the decorator module would become obsolete. However, at present,
-even in Python 3.5 it is impossible to change the function signature
-directly, therefore the ``decorator`` module is still useful.
-Actually, this is the main reasons why I keep maintaining
-the module and releasing new versions.
-It should be noticed that in Python 3.5 a lot of improvements
-have been made: in that version you can decorated a function
-with ``func_tools.update_wrapper`` and ``pydoc`` will see the correct
+However, at present, even in Python 3.5 it is impossible to change the
+function signature directly, therefore the ``decorator`` module is
+still useful. Actually, this is the main reasons why I keep
+maintaining the module and releasing new versions. It should be
+noticed that in Python 3.5 a lot of improvements have been made: in
+that version you can decorated a function with
+``func_tools.update_wrapper`` and ``pydoc`` will see the correct
signature; still internally the function will have an incorrect
-signature, as you can see by using ``inspect.getfullargspec``:
-all documentation tools using such function (which has been
-correctly deprecated) will see the wrong signature.
+signature, as you can see by using ``inspect.getfullargspec``: all
+documentation tools using such function (which has been correctly
+deprecated) will see the wrong signature.
.. _362: http://www.python.org/dev/peps/pep-0362
@@ -1112,7 +1123,7 @@ is added to be consistent with the way ``functools.update_wrapper`` work.
Another attribute which is copied from the original function is
``__qualname__``, the qualified name. This is a concept introduced
in Python 3. In Python 2 the decorator module will still add a
-qualified name, but its value will always be `None`.
+qualified name, but its value will always be ``None``.
"""
import sys