[Python-3000] Type annotations: annotating generators

Guido van Rossum guido at python.org
Fri May 19 02:40:20 CEST 2006

On 5/18/06, Collin Winter <collinw at gmail.com> wrote:
> In working on notes for the type annotations PEP, I've hit some
> ambiguous/unresolved issues in the BDFL annotation syntax (drawing
> primarily from [1] and other blog posts):
> As a quick recap, the syntax looks something like this:
> """def foo(a: int, b: float, c: int = 5) -> list[int]"""
> In looking through all of Guido's blog posts on the subject -- and all
> the comments on them -- I haven't seen anyone consider the case of
> generators. Assuming that "->" makes assertions only about the
> function's return type, if I were to write a generator with the
> following type,
> """def my_range(min: Number, max: Number) -> Number"""
> it would blow up because the function returns a generator, not a Number.

My first response: specify the return type as Generator[Number] so the
whole thing would look like

def my_range(min: Number, max: Number) -> Generator[Number]: ...

> Of course, "->" could be DWIMmy, in the sense that it knows whether
> it's being used in a function or generator context. This doesn't solve
> the other problem with annotating generators, though: send().
> With the BDFL syntax, there's no way to add annotations for a
> generator's send() method. One might suggest something like
> """def my_range(min: Number, max: Number) <- Number -> Number"""
> where "<- Number" indicates that the generator's send() only accepts
> Numbers, but this feels terribly kludgy to me.

I don't like adding syntax specific to generators (especially since
most of the time send() won't be used at all).

I could extend my Generator[Number] example by also allowing
Generator[Number, Number] where the 2nd type would specify the
argument accepted by send(). (Making it 2nd makes it easy to omit.)

Or if you don't like this (I'm not crazy about letting people guess
what the second type is for either) you could write Generator(Number,
send=Number) or even Generator(returns=Number, send=Number). I think
it's fine to specify the return type of the generator by position and
the rest by keyword since the return type is always present.
Generator[Number] and Generator(Number) could mean the same thing
assuming Generator is not a real type like list but a pseudo type only
used for type annotations, like Sequence, Mapping, Iterator etc.

> My own proposal is to use keywords in the vein of "returns", "yields"
> and "is_sent" (don't quibble with the names; the actual names can be
> decided later). Under this modified syntax, the above send() example
> looks something like this:
> """def my_range(min: Number, max: Number) is_sent Number, yields Number"""

That's very ugly IMO.

> In the same spirit, "->" would be replaced with "returns":
> """def foo(a: int, b: float, c: int = 5) returns list[int]"""

I don't like that: 'returns' would have to be a reserved word (there
are no context-dependent reserved words in Python, 'import as'
notwithstanding). It seems you're making everyone suffer for a problem
that occurs only for generators.

> To combat overly long lines, users could wrap the annotation clauses
> to the next line:
> """
> def my_range(min: Number, max: Number) is_sent Number,
>                                        yields Number
> """

The lexer doesn't know enough about the grammer to know that the
newline after the comma should be ignored; adding this to the grammar
would be tricky too since presumably the newline would remain

--Guido van Rossum (home page: http://www.python.org/~guido/)

More information about the Python-3000 mailing list