[Python-ideas] Optional static typing -- the crossroads

Steven D'Aprano steve at pearwood.info
Sun Aug 17 11:41:52 CEST 2014


On Sun, Aug 17, 2014 at 01:52:21AM -0700, Andrew Barnert wrote:
> On Aug 17, 2014, at 0:26, Steven D'Aprano <steve at pearwood.info> wrote:
> 
> > On Sat, Aug 16, 2014 at 11:02:01PM -0700, Andrew Barnert wrote:
> >> 
> > 
> >> I won't belabor the point, but again: I don't think we need a generic 
> >> list type object, and without it, this entire problem--your only 
> >> remaining problem that isn't a mere stylistic choice--vanishes.
> > 
> > I don't understand. If there's no list typing object, how do you declare 
> > a variable must be a list and nothing but a list? Or that it returns a 
> > list?
> 
> You think about it and make sure you really do need a list and nothing 
> but a list. Most of the time (as in all three of the examples given in 
> this thread) this is a mistake. If it's not, then you use List. (Or, 
> if the stdlib doesn't provide that, you have to write one line of 
> code: List = TypeAlias(list), and then you can use it.)

Ah, that is the point I missed. You think that the stdlib shouldn't 
provide a standard typing object for lists, but that people should just 
create their own if they need it.

Okay, but I don't understand why you're singling out lists. If you want 
to propose providing only abstract classes (Sequence, Mapping, etc.) 
and not concrete classes (list, dict, etc.) by default, that makes 
some sense to me. But I don't understand including typing.Dict as 
an alias for dict (say) but not List.


> If having list[T] is going to be more of an attractive nuisance than a 
> useful feature, and it will be especially attractive and nuisanceful 
> for exactly the same novices who are unlikely to know how to TypeAlias 
> it themselves, why is it a problem to leave it out?

There are at least three scenarios:

(1) Built-ins can be used directly in static type annotations:

    x:list[dict]

    This has the advantage of not needing special names, but the 
    disadvantage of encouraging lazy programmers to specify concrete
    types when they should be using abstract Sequence[Mapping].

(2) Built-ins *cannot* be used, you have to import them from typing:

    from typing import List, Dict
    x:List[Dict]

    The advantage is that since you have to do an import anyway,
    it is not much more effort to Do The Right Thing:

    from typing import Sequence, Mapping
    x:Sequence[Mapping]

(3) And the final scenario, the one which confuses me, but seems 
    to be what you are suggesting: you can use the built-ins, 
    *but not list*, and there is no List to import either:

    from typing import Sequence
    x:Sequence[dict]

    I don't understand the advantage of this.


[...]
> >> So, why can't def foo(spam: (int, str)) mean that spam is an 
> >> iterable of an int and a str, in exactly the same way that the 
> >> assignment statement means that a and b are assigned the result of 
> >> unpacking the iterable returned by zip when called with c and d?
> > 
> > But a, b = zip(c, d) requires that there be exactly two elements, not 
> > some unspecified number.
> 
> And spam:(int, str) requires that there be exactly two elements (and 
> that the first be an int and the second a str), not some unspecified 
> number. How is that any different?

Ah, that's what I didn't understand. I thought you meant an iterable of 
either ints or strs, without requiring a fixed number of them.

I must admit, I just assumed that (based on the example of isinstance, 
and general Python practice), unions of types would be represented as a 
tuple, but I see that mypy uses Union[int, str].

In other words, I was thinking:

Iterable[Union[int, str]] == Iterable[(int, str)]

and thought you wanted to drop the Iterable[ ] and just be left with the 
(int, str).


> > To me, spam:(int, str) has a natural interpretation that spam can be 
> > either an int or a str, not an Iterable or Sequence or even a tuple.
> 
> OK, I see the parallel there with exception statements now that you 
> mention it.
> 
> But almost anywhere else in Python, a comma-separated list is a 
> sequence of values, targets, parameters, etc., not a disjunction. The 
> obvious way to spell what you want here is "int | str"

Which mypy spells as Union[ ].

http://mypy-lang.org/tutorial.html



-- 
Steven



More information about the Python-ideas mailing list