summaryrefslogtreecommitdiff
path: root/src/tests/documentation.py
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2015-07-24 08:43:16 +0200
committerMichele Simionato <michele.simionato@gmail.com>2015-07-24 08:43:16 +0200
commit55f28695e817fd7eac8870330843b3dff8f49eaa (patch)
treeaa941ca832e82153ae8499ec557c445e86e51058 /src/tests/documentation.py
parentae96a8f0844770bfb592012ac3ad06cdc7f8e3f9 (diff)
downloadpython-decorator-git-55f28695e817fd7eac8870330843b3dff8f49eaa.tar.gz
Introduced dispatch_info
Diffstat (limited to 'src/tests/documentation.py')
-rw-r--r--src/tests/documentation.py101
1 files changed, 74 insertions, 27 deletions
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index 89dd6ec..04ee70e 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -700,18 +700,18 @@ to dispatch on more than one argument (for instance once I implemented
a database-access library where the first dispatching argument was the
the database driver and the second one was the database record),
but here I prefer to follow the tradition and show the time-honored
-Rock-Paper-Scissor example:
+Rock-Paper-Scissors example:
$$Rock
$$Paper
-$$Scissor
+$$Scissors
-I have added an ordinal to the Rock-Paper-Scissor classes to simplify
+I have added an ordinal to the Rock-Paper-Scissors classes to simplify
the implementation. The idea is to define a generic function ``win(a,
b)`` of two arguments corresponding to the moves of the first and
second player respectively. The moves are instances of the classes
-Rock, Paper and Scissors; Paper wins over Rock, Scissor wins over
-Paper and Rock wins over Scissor. The function will return +1 for a
+Rock, Paper and Scissors; Paper wins over Rock, Scissors wins over
+Paper and Rock wins over Scissors. The function will return +1 for a
win, -1 for a loss and 0 for parity. There are 9 combinations, however
combinations with the same ordinal (i.e. the same class) return 0;
moreover by exchanging the order of the arguments the sign of the
@@ -720,8 +720,8 @@ implementations:
$$win
$$winRockPaper
-$$winPaperScissor
-$$winRockScissor
+$$winPaperScissors
+$$winRockScissors
Here is the result:
@@ -729,23 +729,46 @@ Here is the result:
>>> win(Paper(), Rock())
1
- >>> win(Scissor(), Paper())
+ >>> win(Scissors(), Paper())
1
- >>> win(Rock(), Scissor())
+ >>> win(Rock(), Scissors())
1
>>> win(Paper(), Paper())
0
>>> win(Rock(), Rock())
0
- >>> win(Scissor(), Scissor())
+ >>> win(Scissors(), Scissors())
0
>>> win(Rock(), Paper())
-1
- >>> win(Paper(), Scissor())
+ >>> win(Paper(), Scissors())
-1
- >>> win(Scissor(), Rock())
+ >>> win(Scissors(), Rock())
-1
+The point of generic functions is that they play well with subclassing.
+For instance, suppose we define a StrongRock which does not lose against
+Paper:
+
+$$StrongRock
+$$winStrongRockPaper
+
+Then we do not need to define other implementations, since they are
+inherited from the parent:
+
+.. code-block:: python
+
+ >>> win(StrongRock(), Scissors())
+ 1
+
+You can introspect the precedence used by the dispath algorithm by
+calling ``.dispatch_info(*types)``:
+
+.. code-block:: python
+
+ >>> win.dispatch_info(StrongRock, Scissors)
+ [('StrongRock', 'Scissors'), ('Rock', 'Scissors')]
+
Generic functions and virtual ancestors
-------------------------------------------------
@@ -855,11 +878,24 @@ I will give an example showing the difference:
$$singledispatch_example2
If you play with this example and replace the ``singledispatch`` definition
-with ``functools.singledispatch``, you will see the output change from ``"s"``
-to ``"container"``, because ``functools.singledispatch``
+with ``functools.singledispatch``, the assert will break: ``g`` will return
+``"container"`` instead of ``"s"``, because ``functools.singledispatch``
will insert the ``Container`` class right before ``S``.
+The only way to understand what is happening here is to scratch your
+head by looking at the implementations. I will just notice that
+``.dispatch_info`` is quite useful:
-Finally let me notice that the decorator module implementation does
+.. code-block:: python
+
+ >>> g, V = singledispatch_example2()
+ >>> g.dispatch_info(V)
+ [('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
+in Lisp, nor akin to ``super`` in Python.
+
+Finally, let me notice that the decorator module implementation does
not use any cache, whereas the one in ``singledispatch`` has a cache.
Caveats and limitations
@@ -1411,10 +1447,14 @@ class Paper(object):
ordinal = 1
-class Scissor(object):
+class Scissors(object):
ordinal = 2
+class StrongRock(Rock):
+ pass
+
+
@dispatch_on('a', 'b')
def win(a, b):
if a.ordinal == b.ordinal:
@@ -1429,16 +1469,21 @@ def winRockPaper(a, b):
return -1
-@win.register(Rock, Scissor)
-def winRockScissor(a, b):
+@win.register(Rock, Scissors)
+def winRockScissors(a, b):
return 1
-@win.register(Paper, Scissor)
-def winPaperScissor(a, b):
+@win.register(Paper, Scissors)
+def winPaperScissors(a, b):
return -1
+@win.register(StrongRock, Paper)
+def winStrongRockPaper(a, b):
+ return 0
+
+
class WithLength(object):
def __len__(self):
return 0
@@ -1502,21 +1547,23 @@ def singledispatch_example2():
return 0
@singledispatch
- def j(arg):
+ def g(arg):
return "base"
- @j.register(S)
- def j_s(arg):
+ @g.register(S)
+ def g_s(arg):
return "s"
- @j.register(c.Container)
- def j_container(arg):
+ @g.register(c.Container)
+ def g_container(arg):
return "container"
v = V()
- assert j(v) == "s"
+ assert g(v) == "s"
c.Container.register(V) # add c.Container to the virtual mro of V
- return j(v) # "s", since the virtual mro is V, Sized, S, Container
+ assert g(v) == "s" # since the virtual mro is V, Sized, S, Container
+ return g, V
+
if __name__ == '__main__':
import doctest