[Python-ideas] Conventions for function annotations

Nick Coghlan ncoghlan at gmail.com
Thu Dec 6 06:27:21 CET 2012


On Thu, Dec 6, 2012 at 5:22 AM, Guido van Rossum <guido at python.org> wrote:

> - Composability (Nick's pet peeve, in that he is against it). I
> propose that we reserve plain tuples for this. If an annotation has
> the form "x: (P, Q)" then that ought to mean that x must conform to
> both P and Q. Even though Nick doesn't like this, I don't think we
> should do everything with decorators. Surly, the decorators approach
> is good for certain use cases, and should take precedence if it is
> used. But e.g. IDEs that use annotations for suggestions and
> refactoring should not require everything to be decorated -- that
> would just make the code too busy.
>

I'm not against using composition within a particular set of annotation
semantics, I'm against developing a convention for arbitrary composition of
annotations with *different* semantics.

Instead, I'm advocating for the following guidelines to avoid treading on
each others toes when experimenting with annotations and to leave scope for
us to define standard annotation semantics at a future date:

1. Always use a decorator that expresses the annotation semantics in use
(e.g. tab completion, type descriptions, parameter documentation)
2. Always *move* the annotations out to purpose-specific storage as part of
the decorator (don't leave them in the annotations storage)
3. When analysing a function later, use only the purpose-specific
attribute(s), not the raw annotations storage
4. To support composition with other sets of annotation semantics, always
provide an alternate API that accepts the per-parameter details directly
(e.g. by name or index) rather than relying solely on the annotations

The reason for this is so that if, at some future point in the time,
python-dev agrees to bless some particular set of semantics as *the*
meaning of function annotations (such as the type hinting system being
discussed), then that won't break anything. Otherwise, if people believe
that it's OK for them to simply assume that the contents of the annotations
mean whatever they mean for their particular project, then it *will* cause
problems further down the road as annotations written for one set of
semantics (e.g. tab completion, parameter documentation) get interpreted by
a processor expecting different semantics (e.g. type hinting).

Here's how your example experiment would look under such a scheme:

    from experimental_type_annotations import type_hints, Int, Str, Float

    # After type_hints runs, foo.__annotations__ would be empty, and the
type
    # hinting data would instead be stored in (e.g.) a foo._type_hints
attribute.
    @type_hints
    def foo(a: Int, b: Str) -> Float:
        <blah>

This is then completely clear and unambigious:
- readers can see clearly that these annotations are intended as type hints
- the type hinting processor can see that there *is* type hinting
information available, due to the presence of a _type_hints attribute
- other automated processors see that there are no "default" annotations
(which is good, since there is currently no such thing as "default"
annotation semantics)

Furthermore, (as noted elsewhere in the thread) an alternate API can then
easily be provided that supports composition with other annotations:

    @type_hints(Int, Str, _return=Float)
    def foo(a, b):
        <blah>

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20121206/f60781b4/attachment.html>


More information about the Python-ideas mailing list