Re: [Python-Dev] PEP 443 - Single-dispatch generic functions

2013-05-23 Thread Antoine Pitrou
On Thu, 23 May 2013 12:12:26 +1000
Nick Coghlan ncogh...@gmail.com wrote:
 On Thu, May 23, 2013 at 10:14 AM, Glenn Linderman v+pyt...@g.nevcal.com 
 wrote:
  Yet about half of the operator overloads would be incomplete if there were
  not corresponding __r*__ methods (__radd__, __rsub__, etc.) because the
  second parameter is as key to the dispatch as the first.
 
  While unary operators, and one argument functions would be fully covered by
  single dispatch, it is clear that single dispatch doesn't cover a large
  collection of useful cases for operator overloading.
 
 The binary operators can be more accurately said to use a complicated
 single-dispatch dance rather than supporting native dual-dispatch.

Not one based on the type of a single argument, though. I guess you can
also reduce every function of several arguments to a function accepting
a single tuple of several items, but that doesn't sound very
interesting.

Regards

Antoine.


___
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 - Single-dispatch generic functions

2013-05-23 Thread Devin Jeanpierre
On Thu, May 23, 2013 at 2:04 AM, Antoine Pitrou solip...@pitrou.net wrote:
 On Thu, 23 May 2013 12:12:26 +1000
 Nick Coghlan ncogh...@gmail.com wrote:
 The binary operators can be more accurately said to use a complicated
 single-dispatch dance rather than supporting native dual-dispatch.

 Not one based on the type of a single argument, though.

Why not?

I'd expect it to look something like this:

@singledispatch
def ladd(left, right):
return NotImplemented

@singledispatch
def radd(right, left):
return NotImplemented

def add(left, right):
x = ladd(left, right)
if x is not NotImplemented:
return x
x = radd(right, left)
if x is not NotImplemented:
return x
raise TypeError

Then instead of defining __add__ you define an overloaded
implementation of ladd, and instead of defining __radd__ you define an
overloaded implementation of radd.

-- Devin
___
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 - Single-dispatch generic functions

2013-05-23 Thread Antoine Pitrou
On Thu, 23 May 2013 02:33:57 -0400
Devin Jeanpierre jeanpierr...@gmail.com wrote:
 On Thu, May 23, 2013 at 2:04 AM, Antoine Pitrou solip...@pitrou.net wrote:
  On Thu, 23 May 2013 12:12:26 +1000
  Nick Coghlan ncogh...@gmail.com wrote:
  The binary operators can be more accurately said to use a complicated
  single-dispatch dance rather than supporting native dual-dispatch.
 
  Not one based on the type of a single argument, though.
 
 Why not?
 
 I'd expect it to look something like this:
 
 @singledispatch
 def ladd(left, right):
 return NotImplemented
 
 @singledispatch
 def radd(right, left):
 return NotImplemented
 
 def add(left, right):
 x = ladd(left, right)
 if x is not NotImplemented:
 return x
 x = radd(right, left)
 if x is not NotImplemented:
 return x
 raise TypeError
 
 Then instead of defining __add__ you define an overloaded
 implementation of ladd, and instead of defining __radd__ you define an
 overloaded implementation of radd.

Well, I don't think you can say add() dispatches based on the type of a
single argument. But that may be a question of how you like to think
about decomposed problems.

Regards

Antoine.
___
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 - Single-dispatch generic functions

2013-05-23 Thread Armin Rigo
Hi,

On Thu, May 23, 2013 at 12:33 AM, Łukasz Langa luk...@langa.pl wrote:
 Alternative approaches
 ==

You could also mention pairtype, used in PyPy:
https://bitbucket.org/pypy/pypy/raw/default/rpython/tool/pairtype.py
(very short code).  It's originally about adding double-dispatch, but
the usage that grew out of it is for generic single-dispatch functions
that are bound to some common state object as follows (Python 2
syntax):

class MyRepr(object):
 ...state of my repr...

class __extend__(pairtype(MyRepr, int)):
def show((myrepr, x), y):
 print hi, I'm the integer %d, arg is %s % (x, y)

class __extend__(pairtype(MyRepr, list)):
def show((myrepr, x), y):
 print hi, I'm a list
 ...use myrepr to control the state...

pair(MyRepr(), [2,3,4]).show(42)


- Armin
___
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 - Single-dispatch generic functions

2013-05-23 Thread Nick Coghlan
On 23 May 2013 16:37, Devin Jeanpierre jeanpierr...@gmail.com wrote:

 On Thu, May 23, 2013 at 2:04 AM, Antoine Pitrou solip...@pitrou.net
wrote:
  On Thu, 23 May 2013 12:12:26 +1000
  Nick Coghlan ncogh...@gmail.com wrote:
  The binary operators can be more accurately said to use a complicated
  single-dispatch dance rather than supporting native dual-dispatch.
 
  Not one based on the type of a single argument, though.

 Why not?

 I'd expect it to look something like this:

 @singledispatch
 def ladd(left, right):
 return NotImplemented

 @singledispatch
 def radd(right, left):
 return NotImplemented

 def add(left, right):
 x = ladd(left, right)
 if x is not NotImplemented:
 return x
 x = radd(right, left)
 if x is not NotImplemented:
 return x
 raise TypeError

 Then instead of defining __add__ you define an overloaded
 implementation of ladd, and instead of defining __radd__ you define an
 overloaded implementation of radd.

That's the basic idea, but there's the extra complication that if
type(right) is a strict subclass of type(left), you try radd first.

Cheers,
Nick.


 -- Devin
 ___
 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/ncoghlan%40gmail.com
___
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 - Single-dispatch generic functions

2013-05-23 Thread Glenn Linderman

On 5/23/2013 12:14 AM, Antoine Pitrou wrote:

On Thu, 23 May 2013 02:33:57 -0400
Devin Jeanpierrejeanpierr...@gmail.com  wrote:

On Thu, May 23, 2013 at 2:04 AM, Antoine Pitrousolip...@pitrou.net  wrote:

 On Thu, 23 May 2013 12:12:26 +1000
 Nick Coghlanncogh...@gmail.com  wrote:

 The binary operators can be more accurately said to use a complicated
 single-dispatch dance rather than supporting native dual-dispatch.

 
 Not one based on the type of a single argument, though.


Why not?

I'd expect it to look something like this:

 @singledispatch
 def ladd(left, right):
 return NotImplemented

 @singledispatch
 def radd(right, left):
 return NotImplemented

 def add(left, right):
 x = ladd(left, right)
 if x is not NotImplemented:
 return x
 x = radd(right, left)
 if x is not NotImplemented:
 return x
 raise TypeError

Then instead of defining __add__ you define an overloaded
implementation of ladd, and instead of defining __radd__ you define an
overloaded implementation of radd.

Well, I don't think you can say add() dispatches based on the type of a
single argument. But that may be a question of how you like to think
about decomposed problems.


I suspect the point was not that add can be described as doing single 
dispatch (it can't), but rather that add could possibly be implemented 
in terms of lower-level functions doing single dispatch. If that was the 
point, perhaps the next level point is trying to be that single dispatch 
is a sufficient mechanism that can be augmented (as above) to handle 
more complex cases. Whether the above (which I think would need to use 
raise and try instead of return and if) is sufficient to handle such 
cases is not yet proven. The case Guido mention where radd is tried 
before add would seem to require a bit more complex logic than the above.
___
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 - Single-dispatch generic functions

2013-05-23 Thread Antoine Pitrou
Le Thu, 23 May 2013 00:31:38 -0700,
Glenn Linderman v+pyt...@g.nevcal.com a écrit :
 
 I suspect the point was not that add can be described as doing single 
 dispatch (it can't), but rather that add could possibly be
 implemented in terms of lower-level functions doing single dispatch.
 If that was the point, perhaps the next level point is trying to be
 that single dispatch is a sufficient mechanism that can be augmented
 (as above) to handle more complex cases.

This is true, but as it is of everything Turing-complete. Generic
functions don't add anything that you can't already do manually (for
example with custom registries) :-)

Regardless, I also agree that single-dispatch is much easier to reason
about, and good enough for now.

Regards

Antoine.


___
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 442 delegate

2013-05-23 Thread Kristján Valur Jónsson

 Didn't know about Stackless Python. Is it faster than CPython?
 
 I'm developing an application that takes more than 5000 active threads,
 sometimes up to 10.
 Will it benefit from Stackless Python?
 
 Can I use it for WSGI with Apache httpd?
 
Stackless has its own website and mailing list.
Please visit www.stackless.com for full info, since it is offtopic for this 
list.

K
___
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 - Single-dispatch generic functions

2013-05-23 Thread Łukasz Langa
On 23 maj 2013, at 01:16, Terry Jan Reedy tjre...@udel.edu wrote:

 I like the general idea. Does you have any specific stdlib use cases in mind?
 
 I thought of pprint, which at some point dispatches on dict versus 
 set/sequence, but overall it seems more complicated than mere arg type 
 dispatch.

I want to make pprint extensible for 3.4 and PEP 443 started out as an idea to 
introduce a uniform API for the boilerplate I'm going to need anyway. It turned 
out the idea has been around for years.

 Unittest.TestCase.assertEqual mostly (but not completely) uses first arg 
 dispatch based on an instance-specific dict, and it has an custom instance 
 registration method addTypeEqualityFunc. (Since each test_xxx runs in a new 
 instance, a registration for multiple methods has to be done either in a 
 setup method or repeated in each test_method.)

If a registration mechanism is already in place, it will probably need to stay 
(backwards compatibility). The feasability of refactoring to @singledispatch 
will have to be considered on a case-by-case basis.

On a more general note, I'm sure that @singledispatch won't cover every use 
case. Still, PJE implemented both pkgutil.simplegeneric and PEAK-Rules because 
the former is the proverbial 20% that gets you 80% there. For those use cases 
the simplicity and transparency provided by a basic solution are a virtue. This 
is what PEP 443 targets.

If @singledispatch turns out so successful that we'll find ourselves longing 
for multiple dispatch or predicate-based dispatch in the future, I'm sure 
there's still going to be enough PEP numbers free. The @singledispatch name has 
been chosen to ensure there's no name clash in that case (thanks Nick for 
suggesting that!).

-- 
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 409 and the stdlib

2013-05-23 Thread Martin v. Löwis
Am 21.05.13 18:03, schrieb Ethan Furman:
 And, of course, we only make these changes when we're already modifying
 the module for some other reason.

In the specific case, the KeyError has indeed useful information that
the TypeError does not, namely the specific character that is the culprit.

So if you do drop the KeyError entirely, please carry over information
about the character into the TypeError.

Regards,
Martin

___
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 - Single-dispatch generic functions

2013-05-23 Thread Łukasz Langa
On 23 maj 2013, at 09:33, Armin Rigo ar...@tunes.org wrote:

 Hi,
 
 On Thu, May 23, 2013 at 12:33 AM, Łukasz Langa luk...@langa.pl wrote:
 Alternative approaches
 ==
 
 You could also mention pairtype, used in PyPy:

Thanks for pointing that out. Information on it added
in http://hg.python.org/peps/rev/b7979219f3cc#l1.7

+PyPy's RPython offers ``extendabletype`` [#pairtype]_, a metaclass which
+enables classes to be externally extended. In combination with
+``pairtype()`` and ``pair()`` factories, this offers a form of
+single-dispatch generics.

+.. [#pairtype]
+   https://bitbucket.org/pypy/pypy/raw/default/rpython/tool/pairtype.py


-- 
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 409 and the stdlib

2013-05-23 Thread Ethan Furman

On 05/23/2013 04:36 AM, Martin v. Löwis wrote:

Am 21.05.13 18:03, schrieb Ethan Furman:

And, of course, we only make these changes when we're already modifying
the module for some other reason.


In the specific case, the KeyError has indeed useful information that
the TypeError does not, namely the specific character that is the culprit.

So if you do drop the KeyError entirely, please carry over information
about the character into the TypeError.


Here's the code that existed at one point:

for c in s:
val = _b32rev.get(c)
if val is None:
raise TypeError('Non-base32 digit found')

Even though there is no KeyError to convert in this incarnation, providing the cause of failure is still appreciated by 
the user who's trying to figure out what, exactly, went wrong.


--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread Guido van Rossum
Łukasz, are there any open issues? Otherwise I'm ready to accept the PEP.

-- 
--Guido van Rossum (python.org/~guido)
___
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 - Single-dispatch generic functions

2013-05-23 Thread Łukasz Langa
On 23 maj 2013, at 16:49, Guido van Rossum gu...@python.org wrote:

 Łukasz, are there any open issues? Otherwise I'm ready to accept the PEP.

There's one. Quoting the PEP:

The dispatch type is currently specified as a decorator argument. The
implementation could allow a form using argument annotations. This usage
pattern is out of scope for the standard library (per PEP 8). However,
whether this registration form would be acceptable for general usage, is
up to debate.

I feel that the PEP should explicitly allow or disallow for the
implementation to accept dispatch on annotations, e.g.:

@func.register
def _(arg: int):
  ...

versus

@func.register(int)
def _(arg):
  ...

-- 
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 - Single-dispatch generic functions

2013-05-23 Thread Paul Moore
On 23 May 2013 15:58, Łukasz Langa luk...@langa.pl wrote:

 On 23 maj 2013, at 16:49, Guido van Rossum gu...@python.org wrote:

  Łukasz, are there any open issues? Otherwise I'm ready to accept the PEP.

 There's one. Quoting the PEP:

 The dispatch type is currently specified as a decorator argument. The
 implementation could allow a form using argument annotations. This usage
 pattern is out of scope for the standard library (per PEP 8). However,
 whether this registration form would be acceptable for general usage, is
 up to debate.

 I feel that the PEP should explicitly allow or disallow for the
 implementation to accept dispatch on annotations, e.g.:

 @func.register
 def _(arg: int):
   ...

 versus

 @func.register(int)
 def _(arg):
   ...


Personally, I think the register(int) form seems more natural. But that may
well be because there are no uses of annotations in the wild (at least not
in code I'm familiar with) and having this as an example of how annotations
can be used would help with adoption.

I'm not 100% sure what the options are.

1. Only support the register(int) form
2. Only support the annotation form
3. Support both annotation and argument forms

Is the debate between 1 and 2, or 1 and 3? Is it even possible to implement
3 without having 2 different names for register?

If the debate is between 1 and 2, I'd prefer 1. But if it's between 1 and
3, I'm less sure - having the *option* to try annotations for this in my
own code sounds useful.

Paul.
___
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 - Single-dispatch generic functions

2013-05-23 Thread Guido van Rossum
Ok, happy bikeshedding. I'm outta here until that's settled. :-)

On Thu, May 23, 2013 at 7:58 AM, Łukasz Langa luk...@langa.pl wrote:
 On 23 maj 2013, at 16:49, Guido van Rossum gu...@python.org wrote:

 Łukasz, are there any open issues? Otherwise I'm ready to accept the PEP.

 There's one. Quoting the PEP:

 The dispatch type is currently specified as a decorator argument. The
 implementation could allow a form using argument annotations. This usage
 pattern is out of scope for the standard library (per PEP 8). However,
 whether this registration form would be acceptable for general usage, is
 up to debate.

 I feel that the PEP should explicitly allow or disallow for the
 implementation to accept dispatch on annotations, e.g.:

 @func.register
 def _(arg: int):
   ...

 versus

 @func.register(int)
 def _(arg):
   ...

 --
 Best regards,
 Łukasz Langa

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




-- 
--Guido van Rossum (python.org/~guido)
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ethan Furman

On 05/23/2013 07:58 AM, Łukasz Langa wrote:

On 23 maj 2013, at 16:49, Guido van Rossum gu...@python.org wrote:


Łukasz, are there any open issues? Otherwise I'm ready to accept the PEP.


There's one. Quoting the PEP:

The dispatch type is currently specified as a decorator argument. The
implementation could allow a form using argument annotations. This usage
pattern is out of scope for the standard library (per PEP 8). However,
whether this registration form would be acceptable for general usage, is
up to debate.

I feel that the PEP should explicitly allow or disallow for the
implementation to accept dispatch on annotations, e.g.:

@func.register
def _(arg: int):
   ...

versus

@func.register(int)
def _(arg):
   ...


If the stdlib is still staying out of the annotation business, then it should 
not be allowed.

--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread Walter Dörwald

On 23.05.13 00:33, Łukasz Langa wrote:


Hello,
I would like to submit the following PEP for discussion and evaluation.


PEP: 443
Title: Single-dispatch generic functions
[...]
@fun.register(int)
   ... def _(arg, verbose=False):
   ... if verbose:
   ... print(Strength in numbers, eh?, end= )
   ... print(arg)
   ...


Should it be possible to register multiple types for the generic 
function with one register() call, i.e. should:


   @fun.register(int, float)
   def _(arg, verbose=False):
  ...

be allowed as a synonym for

   @fun.register(int)
   @fun.register(float)
   def _(arg, verbose=False):
  ...

Servus,
   Walter

___
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 - Single-dispatch generic functions

2013-05-23 Thread Paul Moore
On 23 May 2013 17:00, Walter Dörwald wal...@livinglogic.de wrote:

 Should it be possible to register multiple types for the generic function
 with one register() call, i.e. should:

@fun.register(int, float)
def _(arg, verbose=False):
   ...

 be allowed as a synonym for

@fun.register(int)
@fun.register(float)
def _(arg, verbose=False):


No, because people will misread register(int, float) as meaning first
argument int, second float. The double decorator is explicit as to what is
going on, and isn't too hard to read or write.

Paul
___
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 - Single-dispatch generic functions

2013-05-23 Thread Éric Araujo
Hi,

Thanks for writing this PEP.  Blessing one implementation for the stdlib
and one official backport will make programmers’ lives a bit easier :)

@fun.register(int)
   ... def _(arg, verbose=False):
   ... if verbose:
   ... print(Strength in numbers, eh?, end= )
   ... print(arg)
   ...

Does this work if the implementation function is called like the first
decorated function? (I don’t know the proper terminology) e.g.

 @fun.register(int)
... def fun(arg, verbose=False):
... if verbose:
... print(Strength in numbers, eh?, end= )
... print(arg)

The precedent is 2.6+ properties, where prop.setter mutates and returns
the property object, which then overwrites the previous name in the
class dictionary.

 * the current implementation relies on ``__mro__`` alone, making it
   incompatible with Abstract Base Classes'
   ``register()``/``unregister()`` functionality. A possible solution has
   been proposed by PJE on the original issue for exposing
   ``pkgutil.simplegeneric`` as part of the ``functools`` API
   [#issue-5135]_.

Making generic functions work with ABCs sounds like a requirement to me,
as ABCs are baked into the language (isinstance).  ABCs and interfaces
(i.e. zope.interface) are really neat and powerful.

 * the dispatch type is currently specified as a decorator argument. The
   implementation could allow a form using argument annotations. This
   usage pattern is out of scope for the standard library [#pep-0008]_.
   However, whether this registration form would be acceptable for
   general usage, is up to debate.

+1 to passing the type as argument to the decorator and not supporting
annotations.  It’s simple and works.


Question: what happens if two functions (say in two different modules)
are registered for the same type?
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ethan Furman

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:

.. code-block:: pycon

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:

.. code-block:: pycon

@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:

.. code-block:: pycon

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



So to have a generic `mapping` function that worked on dicts, namedtuples, user-defined record types, etc., would look 
something like:


-- from functools import singledispatch

-- @singledispatch
-- def mapping(d):
... new_d = {}
... new_d.update(d)
... return new_d
...

-- @mapping.register(tuple)
... def _(t):
... names = getattr(t, '_fields', ['f%d' % n for n in range(len(t))])
... values = list(t)
... return dict(zip(names, values))
...

-- @mapping.register(user_class):
... def _(uc):
... blah blah
... return dict(more blah)
...

Very cool.  I'm looking forward to it!

Oh, the tuple example above is intended primarily for named tuples, but since there is no common base class besides 
tuple I had to also handle the case where a plain tuple is passed in, and personally I'd rather have generic field names 
than raise an exception.


--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread PJ Eby
On Thu, May 23, 2013 at 11:11 AM, Paul Moore p.f.mo...@gmail.com wrote:
 Is the debate between 1 and 2, or 1 and 3? Is it even possible to implement
 3 without having 2 different names for register?

Yes.  You could do it as either:
@func.register
def doit(foo: int):
...

by checking for the first argument to register() being a function, or:

   @func.register()
def doit(foo: int):
...

by using a default None first argument.  In either case, you would
then raise a TypeError if there wasn't an annotation.

As to the ability to do multiple types registration, you could support
it only in type annotations, e.g.:

@func.register
def doit(foo: [int, float]):
...

without it being confused with being multiple dispatch.

One other thing about the register API that's currently unspecified in
the PEP: what does it return, exactly?

I generally lean towards returning the undecorated function, so that if you say:

@func.register
def do_int(foo: int):
...

You still have the option of calling it explicitly.  OTOH, some may
prefer to treat it like an overload and call it 'func' every time, in
which case register should return the generic function.  Some guidance
as to what should be the official One Obvious Way would be helpful
here.

(Personally, I usually name my methods explicitly because in debugging
it's a fast clue as to which piece of code I should be looking at.)
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ethan Furman

On 05/23/2013 11:13 AM, Éric Araujo wrote:


Thanks for writing this PEP.  Blessing one implementation for the stdlib
and one official backport will make programmers’ lives a bit easier :)


@fun.register(int)
   ... def _(arg, verbose=False):
   ... if verbose:
   ... print(Strength in numbers, eh?, end= )
   ... print(arg)
   ...


Does this work if the implementation function is called like the first
decorated function? (I don’t know the proper terminology) e.g.

  @fun.register(int)
 ... def fun(arg, verbose=False):
 ... if verbose:
 ... print(Strength in numbers, eh?, end= )
 ... print(arg)

The precedent is 2.6+ properties, where prop.setter mutates and returns
the property object, which then overwrites the previous name in the
class dictionary.


Actually, properties return new instances:

-- class Test(object):
... _temp = 'fleeting'
... @property
... def temp(self):
... return self._temp
... @temp.setter
... def new_temp(self, value):
... self._temp = value
...

-- id(Test.temp)
30245384

-- id(Test.new_temp)
30246352

-- Test.temp is Test.new_temp
False

--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread PJ Eby
On Thu, May 23, 2013 at 2:59 PM, PJ Eby p...@telecommunity.com wrote:
 I generally lean towards returning the undecorated function, so that if you 
 say:

 @func.register
 def do_int(foo: int):
 ...

Oops, forgot to mention:  one other advantage to returning the
undecorated function is that you can do this:

@func.register(int)
@func.register(float)
def do_num(foo):
   ...

Which neatly solves the multiple registration problem, even without
argument annotations.
___
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 - Single-dispatch generic functions

2013-05-23 Thread Łukasz Langa
On 23 maj 2013, at 20:59, PJ Eby p...@telecommunity.com wrote:

 As to the ability to do multiple types registration, you could support
 it only in type annotations, e.g.:
 
@func.register
def doit(foo: [int, float]):
...

Initially I thought so, too. But it seems other people might think this
means a sequence with the first element being an integer, and the second
a float. The BDFL seems to have yet a different idea:

http://mail.python.org/pipermail/python-ideas/2012-December/018129.html

This is clearly material for a separate PEP, wink wink, nudge nudge.

To the point though. Based on this, and the fact PEP 8 currently disallows
annotations within the standard library, I came to the conclusion that
currently we should not include the annotation-driven form.

 I generally lean towards returning the undecorated function, so that if you 
 say:
 
@func.register
def do_int(foo: int):
...

Me too. The PEP has been updated to specify that explicitly.

-- 
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 - Single-dispatch generic functions

2013-05-23 Thread Łukasz Langa
On 23 maj 2013, at 20:13, Éric Araujo mer...@netwok.org wrote:

 Does this work if the implementation function is called like the first
 decorated function?

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

 Making generic functions work with ABCs sounds like a requirement to me

Yes, I will implement that.

 Question: what happens if two functions (say in two different modules)
 are registered for the same type?

Last one wins. Just like with assigning names in a scope, defining methods
in a class or overriding them in a subclass.

-- 
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 - Single-dispatch generic functions

2013-05-23 Thread Ethan Furman

On 05/23/2013 01:10 PM, Łukasz Langa wrote:

On 23 maj 2013, at 20:59, PJ Eby p...@telecommunity.com wrote:


As to the ability to do multiple types registration, you could support
it only in type annotations, e.g.:

@func.register
def doit(foo: [int, float]):
...


Initially I thought so, too. But it seems other people might think this
means a sequence with the first element being an integer, and the second
a float. The BDFL seems to have yet a different idea:

http://mail.python.org/pipermail/python-ideas/2012-December/018129.html

This is clearly material for a separate PEP, wink wink, nudge nudge.

To the point though. Based on this, and the fact PEP 8 currently disallows
annotations within the standard library, I came to the conclusion that
currently we should not include the annotation-driven form.


I generally lean towards returning the undecorated function, so that if you say:

@func.register
def do_int(foo: int):
...


Me too. The PEP has been updated to specify that explicitly.


So with this decision made, are there any open issues left?  Or can we invite 
Guido back to the discussion?  ;)

--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ronan Lamy
2013/5/23 Łukasz Langa luk...@langa.pl

 On 23 maj 2013, at 20:13, Éric Araujo mer...@netwok.org wrote:

  Question: what happens if two functions (say in two different modules)
  are registered for the same type?

 Last one wins. Just like with assigning names in a scope, defining methods
 in a class or overriding them in a subclass.


This is a serious annoyance, considering that there are several places
where a large library can reasonably define the implementations (i.e. with
the class, with the function, or in some utility module). Note that in
contrast with the case of functions in a module or methods in a class,
linting tools cannot be expected to detect a duplication between functions
with different names defined in different modules.

Another thing missing from the PEP is the ability to access the
implementation function when you know the generic function and the class. A
major use case for this is to define the implementation for a subclass by
reusing its parent's implementation, e.g. :

@some_generic.register(my_int)
def _(arg):
print(Hello from my_int!)
return some_generic[int](arg)

--
Ronan Lamy
___
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 - Single-dispatch generic functions

2013-05-23 Thread Éric Araujo
Le 23/05/2013 16:10, Łukasz Langa a écrit :
 Does this work if the implementation function is called like the first
 decorated function?
 No, the ``register()`` attribute returns the undecorated function which
 enables decorator stacking, as well as creating unit tests for each
 variant independently.

Perfect.  My web framework of choice uses decorators that register
things and return the function as is and I love it.  I guess the common
pattern will be to use variants of the generic function name, e.g. func
is implemented by func_int, func_str and co, which also helps debugging.

 Making generic functions work with ABCs sounds like a requirement to me
 Yes, I will implement that.

Great!

 Question: what happens if two functions (say in two different modules)
 are registered for the same type?
 Last one wins. Just like with assigning names in a scope, defining methods
 in a class or overriding them in a subclass.

Works for me.

Cheers
___
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 409 and the stdlib

2013-05-23 Thread Steven D'Aprano

On 24/05/13 00:24, Ethan Furman wrote:


Here's the code that existed at one point:

 for c in s:
 val = _b32rev.get(c)
 if val is None:
 raise TypeError('Non-base32 digit found')

Even though there is no KeyError to convert in this incarnation, providing the 
cause of failure is still appreciated by the user who's trying to figure out 
what, exactly, went wrong.


For the record, that is the implementation used in Python 3.3.0rc3, so at some 
point is actually very recently.


--
Steven
___
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 - Single-dispatch generic functions

2013-05-23 Thread Steven D'Aprano

On 24/05/13 01:04, Ethan Furman wrote:

On 05/23/2013 07:58 AM, Łukasz Langa wrote:



I feel that the PEP should explicitly allow or disallow for the
implementation to accept dispatch on annotations, e.g.:

@func.register
def _(arg: int):
   ...

versus

@func.register(int)
def _(arg):
   ...


If the stdlib is still staying out of the annotation business, then it should 
not be allowed.



Perhaps it is time to relax that ruling? The standard library acts as a guide 
to best practice in Python, and I think that uptake of annotations has been 
hurt due to the lack of good examples. Also, anyone with the conceit that their 
library or module may someday be in the standard library cannot afford to use 
annotations at all.

So I'm tentatively +1 on allowing the annotation form in addition to the 
decorator argument form.




--
Steven
___
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 - Single-dispatch generic functions

2013-05-23 Thread Steven D'Aprano

On 24/05/13 02:56, Paul Moore wrote:

On 23 May 2013 17:00, Walter Dörwald wal...@livinglogic.de wrote:


Should it be possible to register multiple types for the generic function
with one register() call, i.e. should:

@fun.register(int, float)
def _(arg, verbose=False):
   ...

be allowed as a synonym for

@fun.register(int)
@fun.register(float)
def _(arg, verbose=False):



No, because people will misread register(int, float) as meaning first
argument int, second float. The double decorator is explicit as to what is
going on, and isn't too hard to read or write.


I don't think that they will. Being able to register multiple types with a single call 
reads very naturally to me, while multiple decorators still looks weird. Even after many 
years of seeing them, I still get a momentary What the hell...? moment when I 
see two decorators on one function. That's only going to be increased when both 
decorators are the same (apart from the argument). The double decorator form above looks 
to me as weird as:

x = func(a)
x = func(b)


would. I have to stop and think about what is going on, and whether or not it 
is a mistake.


So I am a strong +1 on allowing multiple types to be registered in one call.


--
Steven
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ben Hoyt
 So I am a strong +1 on allowing multiple types to be registered in one call.

Yeah, agreed. It also fits the pattern set by isinstance(), which
allows a tuple of types, like isinstance(x, (int, str)).

That said, I'm +0 on this PEP itself. It seems no one has provided
decent use-case examples (apart from contrived ones), from the stdlib
for example. In the fairly large codebase I work on, it'd only be used
in one place, and even there the PEP's approach is arguably too simple
for what we're doing. It seems to me for the few times this would be
used, direct and simple use of isinstance() would be clearer. But
maybe that's just our particular codebase.

-Ben
___
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 - Single-dispatch generic functions

2013-05-23 Thread PJ Eby
On Thu, May 23, 2013 at 6:58 PM, Ben Hoyt benh...@gmail.com wrote:
 It seems no one has provided
 decent use-case examples (apart from contrived ones)

Um, copy.copy(), pprint.pprint(), a bunch of functions in pkgutil
which are actually *based on this implementation already* and have
been since Python 2.5...  I don't see how any of those are contrived
examples.  If we'd had this in already, all the registration-based
functions for copying, pickling, etc. would likely have been
implemented this way, and the motivating example for the PEP is the
coming refactoring of pprint.pprint.
___
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 - Single-dispatch generic functions

2013-05-23 Thread Ethan Furman

On 05/23/2013 02:02 PM, Ronan Lamy wrote:

2013/5/23 Łukasz Langa luk...@langa.pl mailto:luk...@langa.pl

On 23 maj 2013, at 20:13, Éric Araujo mer...@netwok.org 
mailto:mer...@netwok.org wrote:

 Question: what happens if two functions (say in two different modules)
 are registered for the same type?

Last one wins. Just like with assigning names in a scope, defining methods
in a class or overriding them in a subclass.


This is a serious annoyance, considering that there are several places where a 
large library can reasonably define the
implementations (i.e. with the class, with the function, or in some utility 
module). Note that in contrast with the case
of functions in a module or methods in a class, linting tools cannot be 
expected to detect a duplication between
functions with different names defined in different modules.


What would you suggest happen in this case?

--
~Ethan~
___
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 - Single-dispatch generic functions

2013-05-23 Thread Eric Snow
On May 23, 2013 4:37 PM, Steven D'Aprano st...@pearwood.info wrote:

 On 24/05/13 01:04, Ethan Furman wrote:
 If the stdlib is still staying out of the annotation business, then it
should not be allowed.



 Perhaps it is time to relax that ruling? The standard library acts as a
guide to best practice in Python, and I think that uptake of annotations
has been hurt due to the lack of good examples. Also, anyone with the
conceit that their library or module may someday be in the standard library
cannot afford to use annotations at all.

The idea that decorators determine the meaning of annotations (i.e. they
have no meaning without a decorator) really appeals to me.  I don't see the
imperative for this PEP though, but I'm not opposed.  If there were more
discussion and consensus on annotations + decorators I'd be more convinced.

-eric
___
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 - Single-dispatch generic functions

2013-05-23 Thread Eric Snow
On Thu, May 23, 2013 at 7:30 PM, Eric Snow ericsnowcurren...@gmail.com wrote:
 If there were more
 discussion and consensus on annotations + decorators I'd be more convinced.

However, this PEP should not be gated on any such discussion.

-eric
___
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] What if we didn't have repr?

2013-05-23 Thread Fernando Perez
On Tue, 21 May 2013 06:36:54 -0700, Guido van Rossum wrote:

 Actually changing __str__ or __repr__ is out of the question, best we
 can do is discourage makingbthem different. But adding a protocol for
 pprint (with extra parameters to convey options) is a fair idea. I note
 that Nick sggested to use single-dispatch generic functions for this
 though. Both have pros and cons. Post design ideas to python-ideas
 please, not here!

Just in case you guys find this useful, in IPython we've sort of created 
this kind of 'extended repr protocol', described and illustrated here 
with examples:

http://nbviewer.ipython.org/url/github.com/ipython/ipython/raw/master/
examples/notebooks/Custom%20Display%20Logic.ipynb

It has proven to be widely used in practice.

Cheers,

f

___
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 - Single-dispatch generic functions

2013-05-23 Thread Nick Coghlan
On Fri, May 24, 2013 at 11:45 AM, Eric Snow ericsnowcurren...@gmail.com wrote:
 On Thu, May 23, 2013 at 7:30 PM, Eric Snow ericsnowcurren...@gmail.com 
 wrote:
 If there were more
 discussion and consensus on annotations + decorators I'd be more convinced.

 However, this PEP should not be gated on any such discussion.

Right, I think the latest update makes the right call by saying maybe
someday, but not for now.

Cheers,
Nick.

--
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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 - Single-dispatch generic functions

2013-05-23 Thread Nick Coghlan
On Fri, May 24, 2013 at 10:31 AM, PJ Eby p...@telecommunity.com wrote:
 On Thu, May 23, 2013 at 6:58 PM, Ben Hoyt benh...@gmail.com wrote:
 It seems no one has provided
 decent use-case examples (apart from contrived ones)

 Um, copy.copy(), pprint.pprint(), a bunch of functions in pkgutil
 which are actually *based on this implementation already* and have
 been since Python 2.5...  I don't see how any of those are contrived
 examples.  If we'd had this in already, all the registration-based
 functions for copying, pickling, etc. would likely have been
 implemented this way, and the motivating example for the PEP is the
 coming refactoring of pprint.pprint.

We should be able to use it to help deal with the every growing
importer API problem, too. I know that's technically what pkgutil
already uses it for, but elevating this from pkgutil implementation
detail to official stdlib functionality should make it easier to
document properly :)

Cheers,
Nick.

--
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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 - Single-dispatch generic functions

2013-05-23 Thread Nick Coghlan
On Fri, May 24, 2013 at 8:40 AM, Steven D'Aprano st...@pearwood.info wrote:
 I don't think that they will. Being able to register multiple types with a
 single call reads very naturally to me, while multiple decorators still
 looks weird. Even after many years of seeing them, I still get a momentary
 What the hell...? moment when I see two decorators on one function. That's
 only going to be increased when both decorators are the same (apart from the
 argument). The double decorator form above looks to me as weird as:

 x = func(a)
 x = func(b)


 would. I have to stop and think about what is going on, and whether or not
 it is a mistake.

The difference is that this idiom quickly becomes familiar and unexceptional:

@fun.register(float)
@fun.register(Decimal)
def fun_floating_point(arg1, arg2):
...

Oh, OK, 'fun' is a generic function, and we're registering this as
the implementation for floats and Decimals

By contrast, the following are *always* ambiguous at the point of
definition, as it depends on how fun is defined:

@fun.register(float, Decimal)
def fun_floating_point(arg1, arg2):
...

@fun.register([float, Decimal])
def fun_floating_point(arg1, arg2):
...

Is that multiple dispatch? Or is it registering for single dispatch on
multiple different types?

Sure, we could pick the latter meaning for the standard library, but
existing generic function implementations (cited in the PEP) use the
tuple-of-types notation for multiple dispatch.

By opting for stacking decorators in the PEP and hence the stdlib, we
leave the way clear for 3rd party multi-dispatch libraries to use
multiple type arguments without introducing any ambiguity.

 So I am a strong +1 on allowing multiple types to be registered in one call.

Whereas I'm a strong -1, as the ambiguity problem it would create is
persistent and irreversible, while stacking registration decorators is
just a new idiom to become accustomed to.

Cheers,
Nick.
___
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