docs for multimethods
This commit is contained in:
parent
b7c95d92aa
commit
93676b2ed3
15
doc/_themes/generic/static/basic.css_t
vendored
15
doc/_themes/generic/static/basic.css_t
vendored
@ -589,6 +589,11 @@ div.viewcode-block:target {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
span.pre {
|
||||
background: #e8e8e8;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- autodoc --------------------------------------------------------------- */
|
||||
|
||||
dl.class,
|
||||
@ -596,6 +601,16 @@ dl.module,
|
||||
dl.function {
|
||||
font-size: 90%;
|
||||
}
|
||||
dl.class a,
|
||||
dl.module a,
|
||||
dl.function a {
|
||||
text-decoration: none;
|
||||
}
|
||||
dl.class a:hover,
|
||||
dl.module a:hover,
|
||||
dl.function a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
|
@ -8,7 +8,8 @@ classes then calling such method would execute different implementation based on
|
||||
type of object you call this method on.
|
||||
|
||||
Generic provides another way of implementing subtype polymorphism in Python --
|
||||
multidispatching in form of *multifunctions* and *multimethods*.
|
||||
multidispatching in form of *multifunctions* and *multimethods*. All
|
||||
functionality is provided via ``generic.multidispatch`` module.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@ -34,12 +35,18 @@ desired level of extensibility::
|
||||
def sound(o):
|
||||
print "Meow!"
|
||||
|
||||
This works as expected::
|
||||
Each separate definition of ``sound`` function works for different argument
|
||||
types, we will call each such definition *a multifunction case* or simply *a
|
||||
case*. We can test if our ``sound`` multifunction works as expected::
|
||||
|
||||
>>> sound(Dog())
|
||||
Woof!
|
||||
>>> sound(Cat())
|
||||
Meow!
|
||||
>>> sound(Duck())
|
||||
Traceback
|
||||
...
|
||||
TypeError
|
||||
|
||||
The main advantage of using multifunctions over single function with a bunch of
|
||||
``isinstance`` checks is extensibility -- you can add more cases for other types
|
||||
@ -57,15 +64,17 @@ multifunction *dispatches* on this argument.
|
||||
Multifunctions of several arguments
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can also have multifunctions of several arguments, you can even decide on
|
||||
which of the first arguments you want to dispatch. For example the following function
|
||||
will only dispatch on its first argument while requiring both of them::
|
||||
You can also have multifunctions of several arguments and even decide on
|
||||
which of the first arguments you want to dispatch. For example the following
|
||||
function will only dispatch on its first argument while requiring both of them::
|
||||
|
||||
@multifunction(Dog)
|
||||
def walk(dog, meters):
|
||||
print "Dog walks for %d meters" % meters
|
||||
|
||||
Next example demonstrates multifunction which dispatches on its both arguments::
|
||||
But sometimes you want multifunctions to dispatch on more than one argument, the
|
||||
you just have to provide several arguments to ``multifunction`` decorator and to
|
||||
subsequent ``when`` decorators::
|
||||
|
||||
@multifunction(Dog, Cat)
|
||||
def is_chases(dog, cat):
|
||||
@ -86,17 +95,75 @@ used for dispatch.
|
||||
Providing "catch-all" case
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Overriding cases
|
||||
~~~~~~~~~~~~~~~~
|
||||
There should be an analog to ``else`` statement -- a case which is used when no
|
||||
matching case is found, we will call such case *a catch-all case*, here is how
|
||||
you can define it using ``otherwise`` decorator::
|
||||
|
||||
@sound.otherwise
|
||||
def sound(o):
|
||||
print "<unknown>"
|
||||
|
||||
You can try calling ``sound`` with whatever argument type you wish, it will
|
||||
never fall with ``TypeError`` anymore.
|
||||
|
||||
Multimethods
|
||||
------------
|
||||
|
||||
Inheritance with multimethods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Another functionality provided by ``generic.multidispatch`` module are
|
||||
*multimethods*. Multimethods are similar to multifunctions except they are...
|
||||
methods. Technically the main and the only difference between multifunctions and
|
||||
multimethods is the latter is also dispatch on ``self`` argument.
|
||||
|
||||
Multidispatching vs. subclassing
|
||||
--------------------------------
|
||||
Implementing multimethods is similar to implementing multifunctions, you just
|
||||
have to decorate your methods with ``multimethod`` decorator instead of
|
||||
``multifunction``. But there's some issue with how Python's classes works which
|
||||
forces us to use also ``has_multimethods`` class decorator::
|
||||
|
||||
from generic.multidispatch import multimethod, has_multimethods
|
||||
|
||||
@has_multimethods
|
||||
class Animal(object):
|
||||
|
||||
@multimethod(Vegetable)
|
||||
def can_eat(self, food):
|
||||
return True
|
||||
|
||||
@can_eat.when(Meat)
|
||||
def can_eat(self, food):
|
||||
return False
|
||||
|
||||
This would work like this::
|
||||
|
||||
>>> animal = Animal()
|
||||
>>> animal.can_eat(Vegetable())
|
||||
True
|
||||
>>> animal.can_eat(Meat())
|
||||
False
|
||||
|
||||
So far we haven't seen any differences between multifunctions and multimethods
|
||||
but as it have already been said there's one -- multimethods use ``self``
|
||||
argument for dispatch. We can see that if we would subclass our ``Animal`` class
|
||||
and override ``can_eat`` method definition::
|
||||
|
||||
@has_multimethods
|
||||
class Predator(Animal):
|
||||
|
||||
@Animal.can_eat.when(Meat)
|
||||
def can_eat(self, food):
|
||||
return True
|
||||
|
||||
This will redefine ``can_eat`` method on ``Predator`` instances but the *only*
|
||||
for case for ``Meat`` argument, we can check if with ``Vegetable`` behaviour is
|
||||
the same::
|
||||
|
||||
>>> predator = Predator()
|
||||
>>> predator.can_eat(Vegetable())
|
||||
True
|
||||
>>> predator.can_eat(Meat())
|
||||
True
|
||||
|
||||
The only thing to care is you should not forget to include ``@has_multimethods``
|
||||
decorator on classes which define or override multimethods.
|
||||
|
||||
API reference
|
||||
-------------
|
||||
|
Loading…
Reference in New Issue
Block a user