[Python-3000] Type parameterization (was: Re: Type annotations: annotating generators)
collinw at gmail.com
Fri May 19 04:24:03 CEST 2006
On 5/18/06, Guido van Rossum <guido at python.org> wrote:
> On 5/18/06, Collin Winter <collinw at gmail.com> wrote:
> > 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]: ...
> 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).
This leads nicely into another question I was going to raise : )
BDFL syntax has generally used "Sometype[parameterizer]" to indicate
type parameterization. With this Generator example, you've gone ahead
and implicitly addressed several of the more general questions I had
about parameterization (but since explicit is better than
1. As above, I've occasionally seen "Sometype(parameterizer)" used to
indicate parameterization, but the bracket-based syntax predominates;
can I get a pronouncement endorsing the bracket version as "official"?
2. You've used keyword parameters in the above parens-based example; I
take it these will be legal in all parameterizations?
If yes, this would offer a solution to something I haven't seen
addressed in any blog posts: how to parameterize dict. Plenty of
examples show parameterizations of list, tuple, set, etc using
Use of positional arguments to parameterize dict, e.g., dict[str,
Number], is ugly, but keyword arguments would allow the prettier
dict[key=str, value=Number] (which might also be another use case for
the proposed keyword-only arguments).
Now for some more specific questions:
3. What does list mean (i.e., brackets without a parameterizer)? Is
it an error? An empty list (the list *must* be empty)? Is it different
from a type annotation of list (without brackets)?
Similarly, can you do something like list[Number, String] to assert
that the list instance must have an length evenly divisible by two and
consisting of alternating Numbers and Strings? (That is, [4, 'abc',
7.0, 'foo'] is valid but [4, 'abc', 7.0] is not.)
4. In one blog post, tuple[Number] is described as creating a tuple of
arbitrary length with Number elements, with something like (Number *
Number * String) used to create a 3-tuple. Could we drop the cartesian
product notation for this latter usage and use tuple[Number, Number,
> 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.
This gets into another question: will user-defined annotation classes
be able to use the same parameterization notation?
I'd like to see the typechecking machinery ignore differences like
"real type" v "pseudo type", looking only at whether, zB, a
__parameterize__ method is present. Using __parameterize__ method (or
some other name) allows maximum flexibility with respect to type
For example, the built-in list type might not allow the patterned
parameterization I asked about above. A user might choose to subclass
list to provide this, giving the subclass a __parameterize__ method
def __parameterize__(cls, *vargs):
More information about the Python-3000