summaryrefslogtreecommitdiff
path: root/README.rst
blob: 802ab5e1ff0068684b448c93f1148988d5c9df56 (plain)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
==============
singledispatch
==============

`PEP 443 <http://www.python.org/dev/peps/pep-0443/>`_ proposed to expose
a mechanism in the ``functools`` standard library module in Python 3.4
that provides a simple form of generic programming known as
single-dispatch generic functions.

This library is a backport of this functionality to Python 2.6 - 3.3.

To define a generic function, decorate it with the ``@singledispatch``
decorator. Note that the dispatch happens on the type of the first
argument, create your function accordingly::

  >>> from functools import singledispatch
  >>> @singledispatch
  ... def fun(arg, verbose=False):
  ...     if verbose:
  ...         print("Let me just say,", end=" ")
  ...     print(arg)

To add overloaded implementations to the function, use the
``register()`` attribute of the generic function. It takes a type
parameter::

  >>> @fun.register(int)
  ... def _(arg, verbose=False):
  ...     if verbose:
  ...         print("Strength in numbers, eh?", end=" ")
  ...     print(arg)
  ...
  >>> @fun.register(list)
  ... def _(arg, verbose=False):
  ...     if verbose:
  ...         print("Enumerate this:")
  ...     for i, elem in enumerate(arg):
  ...         print(i, elem)

To enable registering lambdas and pre-existing functions, the
``register()`` attribute can be used in a functional form::

  >>> def nothing(arg, verbose=False):
  ...     print("Nothing.")
  ...
  >>> fun.register(type(None), nothing)

The ``register()`` attribute returns the undecorated function which
enables decorator stacking, pickling, as well as creating unit tests for
each variant independently::

  >>> @fun.register(float)
  ... @fun.register(Decimal)
  ... def fun_num(arg, verbose=False):
  ...     if verbose:
  ...         print("Half of your number:", end=" ")
  ...     print(arg / 2)
  ...
  >>> fun_num is fun
  False

When called, the generic function dispatches on the first argument::

  >>> fun("Hello, world.")
  Hello, world.
  >>> fun("test.", verbose=True)
  Let me just say, test.
  >>> fun(42, verbose=True)
  Strength in numbers, eh? 42
  >>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
  Enumerate this:
  0 spam
  1 spam
  2 eggs
  3 spam
  >>> fun(None)
  Nothing.
  >>> fun(1.23)
  0.615

To get the implementation for a specific type, use the ``dispatch()``
attribute::

  >>> fun.dispatch(float)
  <function fun_num at 0x104319058>
  >>> fun.dispatch(dict)
  <function fun at 0x103fe4788>

To access all registered overloads, use the read-only ``registry``
attribute::

  >>> fun.registry.keys()
  dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,
            <class 'decimal.Decimal'>, <class 'list'>,
            <class 'float'>])
  >>> fun.registry[float]
  <function fun_num at 0x1035a2840>
  >>> fun.registry[object]
  <function fun at 0x103170788>

The vanilla documentation is available at
http://docs.python.org/3/library/functools.html#functools.singledispatch.


Versioning
----------

This backport is intended to keep 100% compatibility with the vanilla
release in Python 3.4+. To help maintaining a version you want and
expect, a versioning scheme is used where:

* the first three numbers indicate the version of Python 3.x from which the
  backport is done

* a backport release number is provided after the last dot

For example, ``3.4.0.0`` is the **first** release of ``singledispatch``
compatible with the library found in Python **3.4.0**.

A single exception from the 100% compatibility principle is that bugs
fixed before releasing another minor Python 3.x.y version **will be
included** in the backport releases done in the mean time. This rule
applies to bugs only.


Maintenance
-----------

This backport is maintained on BitBucket by Ɓukasz Langa, one of the
members of the core CPython team:

* `singledispatch Mercurial repository <https://bitbucket.org/ambv/singledispatch>`_

* `singledispatch issue tracker <https://bitbucket.org/ambv/singledispatch/issues>`_


Change Log
----------

3.4.0.0
~~~~~~~

* the first public release compatible with 3.4.0


Conversion Process
------------------

This section is technical and should bother you only if you are
wondering how this backport is produced. If the implementation details
of this backport are not important for you, feel free to ignore the
following content.

``singledispatch`` is converted using `six
<http://pypi.python.org/pypi/six>`_ so that a single codebase can be
used for all compatible Python versions.  Because a fully automatic
conversion was not doable, I took the following branching approach:

* the ``upstream`` branch holds unchanged files synchronized from the
  upstream CPython repository. The synchronization is currently done by
  manually copying the required code parts and stating from which
  CPython changeset they come from. The tests should pass on Python 3.4
  on this branch.

* the ``default`` branch holds the manually translated version and this
  is where all tests are run for all supported Python versions using
  Tox.