[Python-Dev] PEP 443 - request for pronouncement
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
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
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
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