[Python-ideas] Optional static typing -- the crossroads
Steven D'Aprano
steve at pearwood.info
Sun Aug 17 09:26:02 CEST 2014
On Sat, Aug 16, 2014 at 11:02:01PM -0700, Andrew Barnert wrote:
> On Aug 16, 2014, at 22:03, Guido van Rossum <guido at python.org> wrote:
>
> > Moving on to (2), the proposal is elegant enough by itself, and indeed has the advantage of being clear and concise: [T] instead of List[T], {T: U} instead of Dict[T, U], and so on. However, there are a few concerns.
> >
> > My first concern is that these expressions are only unambiguous in the context of function annotations.
>
> Good point. Together with your third point (that [str] could be
> meaningful as a different type of annotation, while Iterable[str] is
> incredibly unlikely to mean anything other than a static type
> check--except maybe a runtime type check, but I think it's reasonable
> to assume they can share annotations), I think this kills the idea.
> Pity, because I like the way it looked.
[str] looks nice, but it looks like a list of str, or possibly an
optional str, e.g. from the docstring of int:
int(x[, base]) -> integer
What the [str] syntax doesn't look like is an Iterable of str. Or should
that be Sequence of str? MutableSequence perhaps? If [str] means
something other than list of str, it is going to be some arbitrary
special case to be memorized.
Have pity on people teaching Python. I don't want to have to try to
explain to beginners why [str] sometimes means a list and sometimes an
arbitrary Iterable (or whatever). This is just downright confusing:
def func(arg:[str]):
x = [str]
assert isinstance(x, list) # Always passes.
assert isinstance(arg, list) # Sometimes fails.
func(iter("abc")) # Fails.
[Guido]
> > All in all I prefer the mypy syntax, despite being somewhat more
> > verbose and requiring an import, with one caveat: I agree that it
> > would be nicer if the mypy abstract collection types were the same
> > objects as the ABCs exported by collections.abc. I'm not quite sure
> > whether we should also change the concrete collection types from
> > List, Dict, Set, Tuple to list, dict, set, tuple;
We can start with typing.List, Dict, etc., and later on consider using
builtins.
I worry that if we use builtins, people will declare x:list[int] not
because they *need* a list of int, but because it saves typing over
from typing import Sequence, Integer
def func(x:Sequence[Integer]):
So even though I suggested earlier that the builtins grow appropriate
__getitem__ methods, on second thoughts I would be very cautious about
introducing that.
> > the concrete types
> > are so ubiquitous that I worry that there may be working code out
> > there that somehow relies on the type objects themselves not being
> > subscriptable.
[Andrew]
> 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?
[Guido]
> > A mostly unrelated issue: there are two different uses of tuples,
> > and we need a notation for both. One is a tuple of fixed length with
> > heterogeneous, specific types for the elements; for example
> > Tuple[int, float]. But I think we also need a way to indicate that a
> > function expects (or returns) a variable-length tuple with a
> > homogeneous element type.
Throwing this idea out to be shot down: use some sort of slice notation.
Tuple[int, float, str] # Like (23, 1.5, "spam")
Tuple[::int, float, str] # Like (1, 2, 3, 4) or (1.5,) or ("x", "y")
That is, if the argument to __getitem__ is a slice (None, None, T), T is
either a type or a tuple of types. Any other kind of slice is reserved
for the future, or an error.
> > Perhaps we should call this type
> > frozenlist, analogous to frozenset (and it seems there's a proposal
> > for frozendict making the rounds as well).
[Andrew]
> Even if you drop the idea for [str] and {int: str}, which I agree
> seems unavoidable, I think it may still make sense for (int, str) to
> mean a heterogeneous iterable.
That makes no sense to me. It looks like a tuple, not a generic iterable
object. Your interpretation has the same problems I discussed above for
[str] notation: it is an arbitrary choice whether (...) means Iterable,
Sequence or ImmutableSequence, and it doesn't fit nicely with other
common uses of parens. See below.
> Python already has target lists, argument lists, parameter lists, and
> expression lists that all have the same syntax as tuples or a superset
> thereof, but don't define tuples. In (a, b) = zip(c, d), neither (a,
> b) nor (c, d) is a tuple, and I don't think anyone is confused by
> that.
Ha , you've obviously stopped reading the "Multi-line with statement"
thread on Python-Dev :-)
> 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.
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.
> And this leaves Tuple[str] or tuple[str] free to mean a homogenous
> tuple (although, again, I don't think we even want or need that...).
We do. Consider the isinstance() function. Here's the signature
according to its docstring:
isinstance(object, class-or-type-or-tuple) -> bool
The second argument can be a single type, or a tuple of an arbitrary
number of types. I'd write it with annotations like:
def isinstance(object:Any,
class_or_type_or_tuple:(Type, Tuple[::Type])
)->Bool:
assuming (a,b) means "either a or b" and Tuple[::a] means a homogenous
tuple of a. (With shorter argument names, it even fits on one line.)
And, here's issubclass:
def issubclass(C:Type, D:(Type, Tuple[::Type]))->Bool:
--
Steven
More information about the Python-ideas
mailing list