[Python-ideas] Optional static typing -- the crossroads
Steven D'Aprano
steve at pearwood.info
Sun Aug 17 12:20:59 CEST 2014
On Sat, Aug 16, 2014 at 10:03:48PM -0700, Guido van Rossum wrote:
> I'd like to summarize the main issues that have come up. As an experiment,
> I'm not changing the subject, but I am still not quoting anything in
> particular. Only two issues (or issue clusters) really seem contentious:
>
> (1) Should the function annotation syntax (eventually) be reserved for type
> annotations in a standard syntax?
Reserved, as in alternatives are prohibited? No.
But assumed to be types by default? I think so.
> Or can multiple different uses of
> annotations coexist? And if they can, how should a specific use be
> indicated? (Also, some questions about compile-time vs. run-time use.)
Determining whether annotations should be interpreted as type
annotations or not needs to be possible both at compile-time and
run-time. I suggest a special decorator, imported from the typing
module:
from typing import skip_types # or some better name?
@skip_types(marker) # see below for the purpose of marker
@another_decorator # the order of decorators doesn't matter
def function(x:"this is not a type")->[int]:
...
At compile-time, static typing tools should treat any function decorated
by skip_types as if it were dynamic.
The skip_types decorator also writes marker to the __annotations__ dict,
using a key which cannot be used as an identifier. Say, "+mark+". The
purpose of the marker is so that other tools can determine whether the
annotations are aimed at them.
def handle_annotations(func):
if func.__annotations__.get("+mark+", None) is MyMarker:
do_stuff(func.__annotations__)
else:
pass
Any time a function is not decorated by skip_types (or whatever name it
has), or doesn't have that "+mark+" key in the __annotations__ dict,
static type checking tools are entitled to assume the annotations are
used for typing.
> (2) For type annotations, should we adopt (roughly) the mypy syntax or the
> alternative proposed by Dave Halter? This uses built-in container notations
> as a shorthand, e.g. {str: int} instead of Dict[str, int]. This also
> touches on the issue of abstract vs. concrete types (e.g. iterable vs.
> list).
I prefer the mypy syntax.
> Regarding (1), I continue to believe that we should eventually reserve
> annotations for types, to avoid confusing both humans and tools, but I
> think there's nothing we have to do in 3.5 -- 3.5 must preserve backward
> compatibility, and we're not proposing to give annotations any new
> semantics anyway -- the actual changes to CPython are limited to a new
> stdlib module (typing) and some documentation.
>
> Perhaps a thornier issue is how mypy should handle decorators that
> manipulate the signature or annotations of the function they wrap. But I
> think the only reasonable answer here can be that mypy must understand what
> decorators do if it wants to have any chance at type-checking decorated
> functions.
Hmmm. Anything the decorators do to the annotations will be at runtime,
so is it reasonable to say that the static typing tool will only operate
on the annotations available at compile time?
That is, given:
@mangle_annotations
def spam(x:int)->List[str]: ...
the type checker is expected to use the annotations seen at
compile-time, no matter what the mangle_annotations decorator happens to
do at run-time.
Otherwise, the type-checker needs to be a full Python interpreter, in
order to see what mangle_annotations does. And that could be an
intractible problem:
def mangle_annotations(func):
if random.random() < 0.5:
func.__annotations__['x'] = List[str]
else:
func.__annotations__['x'] = float
I don't see how any type-checker is supposed to take that into account.
(1) Compile-time type checkers should ignore the decorator and just use
the annotations available at compile-time;
(2) Run-time analysis tools should use the annotations available at
run-time;
(3) If they happen to be different, oh well, consenting adults.
--
Steven
More information about the Python-ideas
mailing list