[Python-Dev] PEP 443 - request for pronouncement

2013-05-31 Thread Łukasz Langa
Hello python-dev,

PEP 443 is ready for final review. I'm attaching the latest
version below for convenience. The full history of changes
is available here: http://hg.python.org/peps/log/tip/pep-0443.txt

A reference implementation for PEP 443 is available at:
http://hg.python.org/features/pep-443/file/tip/Lib/functools.py#l363

with relevant tests here:
http://hg.python.org/features/pep-443/file/tip/Lib/test/test_functools.py#l855

and documentation here:
http://hg.python.org/features/pep-443/file/tip/Doc/library/functools.rst#l189

There's also an official backport for 2.6 - 3.3 already up:
https://pypi.python.org/pypi/singledispatch



PEP: 443
Title: Single-dispatch generic functions
Version: $Revision$
Last-Modified: $Date$
Author: Łukasz Langa luk...@langa.pl
Discussions-To: Python-Dev python-dev@python.org
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 22-May-2013
Post-History: 22-May-2013, 25-May-2013, 31-May-2013
Replaces: 245, 246, 3124


Abstract


This PEP proposes a new mechanism in the ``functools`` standard library
module that provides a simple form of generic programming known as
single-dispatch generic functions.

A **generic function** is composed of multiple functions implementing
the same operation for different types. Which implementation should be
used during a call is determined by the dispatch algorithm. When the
implementation is chosen based on the type of a single argument, this is
known as **single dispatch**.


Rationale and Goals
===

Python has always provided a variety of built-in and standard-library
generic functions, such as ``len()``, ``iter()``, ``pprint.pprint()``,
``copy.copy()``, and most of the functions in the ``operator`` module.
However, it currently:

1. does not have a simple or straightforward way for developers to
   create new generic functions,

2. does not have a standard way for methods to be added to existing
   generic functions (i.e., some are added using registration
   functions, others require defining ``__special__`` methods, possibly
   by monkeypatching).

In addition, it is currently a common anti-pattern for Python code to
inspect the types of received arguments, in order to decide what to do
with the objects. For example, code may wish to accept either an object
of some type, or a sequence of objects of that type.

Currently, the obvious way to do this is by type inspection, but this
is brittle and closed to extension. Abstract Base Classes make it easier
to discover present behaviour, but don't help adding new behaviour.
A developer using an already-written library may be unable to change how
their objects are treated by such code, especially if the objects they
are using were created by a third party.

Therefore, this PEP proposes a uniform API to address dynamic
overloading using decorators.


User API


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 is a decorator,
taking a type parameter and decorating a function implementing the
operation for that type::

   @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 type of 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

Where there is no registered implementation for a specific type, its
method resolution order is used to find a more generic implementation.
To check which implementation will the generic 

Re: [Python-Dev] PEP 443 - request for pronouncement

2013-05-31 Thread Łukasz Langa
On 31 maj 2013, at 12:18, Gustavo Carneiro gjcarne...@gmail.com wrote:

 It is not clear from the PEP (up until the end of the User API section at 
 least) when, if ever, is this implementation of fun ever called.  I mean, 
 what type of 'arg' triggers a dispatch to this function body?

I added a sentence clarifying that. See the commit:
http://hg.python.org/peps/rev/4d6c827944c4

Does that address your concern?


 So my comment is just about clarity of the PEP text.  I do not wish to 
 interfere with pronouncement.

Sure thing. Thanks for your feedback!


-- 
Best regards,
Łukasz Langa

WWW: http://lukasz.langa.pl/
Twitter: @llanga
IRC: ambv on #python-dev

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 443 - request for pronouncement

2013-05-31 Thread Gustavo Carneiro
On Fri, May 31, 2013 at 11:34 AM, Łukasz Langa luk...@langa.pl wrote:

 On 31 maj 2013, at 12:18, Gustavo Carneiro gjcarne...@gmail.com wrote:

  It is not clear from the PEP (up until the end of the User API section
 at least) when, if ever, is this implementation of fun ever called.  I
 mean, what type of 'arg' triggers a dispatch to this function body?

 I added a sentence clarifying that. See the commit:
 http://hg.python.org/peps/rev/4d6c827944c4

 Does that address your concern?


Yes, much better now.  Thank you!
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 443 - request for pronouncement

2013-05-31 Thread Gustavo Carneiro
Sorry, maybe I am too late to comment on this, but,

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

It is not clear from the PEP (up until the end of the User API section at
least) when, if ever, is this implementation of fun ever called.  I mean,
what type of 'arg' triggers a dispatch to this function body?
I am guessing that when the arg does not match the type of any of the other
registered functions, this function body is used by default.  But it is
only a guess, the PEP doesn't state this clearly.

If my guess is true, would it be reasonable to update the example def fun
code to reflect this, e.g., to print(Warning: I do not know what to do
with arg {} of type {}.format(arg, type(arg)).

So my comment is just about clarity of the PEP text.  I do not wish to
interfere with pronouncement.

Thanks.



On Fri, May 31, 2013 at 10:46 AM, Łukasz Langa luk...@langa.pl wrote:

 Hello python-dev,

 PEP 443 is ready for final review. I'm attaching the latest
 version below for convenience. The full history of changes
 is available here: http://hg.python.org/peps/log/tip/pep-0443.txt

 A reference implementation for PEP 443 is available at:
 http://hg.python.org/features/pep-443/file/tip/Lib/functools.py#l363

 with relevant tests here:

 http://hg.python.org/features/pep-443/file/tip/Lib/test/test_functools.py#l855

 and documentation here:

 http://hg.python.org/features/pep-443/file/tip/Doc/library/functools.rst#l189

 There's also an official backport for 2.6 - 3.3 already up:
 https://pypi.python.org/pypi/singledispatch



 PEP: 443
 Title: Single-dispatch generic functions
 Version: $Revision$
 Last-Modified: $Date$
 Author: Łukasz Langa luk...@langa.pl
 Discussions-To: Python-Dev python-dev@python.org
 Status: Draft
 Type: Standards Track
 Content-Type: text/x-rst
 Created: 22-May-2013
 Post-History: 22-May-2013, 25-May-2013, 31-May-2013
 Replaces: 245, 246, 3124


 Abstract
 

 This PEP proposes a new mechanism in the ``functools`` standard library
 module that provides a simple form of generic programming known as
 single-dispatch generic functions.

 A **generic function** is composed of multiple functions implementing
 the same operation for different types. Which implementation should be
 used during a call is determined by the dispatch algorithm. When the
 implementation is chosen based on the type of a single argument, this is
 known as **single dispatch**.


 Rationale and Goals
 ===

 Python has always provided a variety of built-in and standard-library
 generic functions, such as ``len()``, ``iter()``, ``pprint.pprint()``,
 ``copy.copy()``, and most of the functions in the ``operator`` module.
 However, it currently:

 1. does not have a simple or straightforward way for developers to
create new generic functions,

 2. does not have a standard way for methods to be added to existing
generic functions (i.e., some are added using registration
functions, others require defining ``__special__`` methods, possibly
by monkeypatching).

 In addition, it is currently a common anti-pattern for Python code to
 inspect the types of received arguments, in order to decide what to do
 with the objects. For example, code may wish to accept either an object
 of some type, or a sequence of objects of that type.

 Currently, the obvious way to do this is by type inspection, but this
 is brittle and closed to extension. Abstract Base Classes make it easier
 to discover present behaviour, but don't help adding new behaviour.
 A developer using an already-written library may be unable to change how
 their objects are treated by such code, especially if the objects they
 are using were created by a third party.

 Therefore, this PEP proposes a uniform API to address dynamic
 overloading using decorators.


 User API
 

 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 is a decorator,
 taking a type parameter and decorating a function implementing the
 operation for that type::

@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