[Python-ideas] Proposal: Use mypy syntax for function annotations

Guido van Rossum guido at python.org
Mon Aug 25 19:26:01 CEST 2014


On Mon, Aug 25, 2014 at 6:57 AM, Antoine Pitrou <antoine at python.org> wrote:

>
> Le 24/08/2014 23:12, Guido van Rossum a écrit :
>
> > As I have said several times now, it fulfills exactly the original
> > (pre-PEP 3107) goal I had in mind for them.
>
> But were you envisioning back then that said annotations would be
> looked up without the regular execution environment?
>
> PEP 3107 doesn't say anything about that (or rather, it says that
> annotations can be looked up on the function, but function objects only
> exist at run-time). Actually, the bytecode isn't very practical to work
> with to extract annotations, it seems:
>
> >>> def g():
> ...   def f(a: "foo") -> "bar": pass
> ...
> >>> dis.dis(g)
>   2           0 LOAD_CONST               1 ('foo')
>               3 LOAD_CONST               2 ('bar')
>               6 LOAD_CONST               3 (('a', 'return'))
>               9 LOAD_CONST               4 (<code object f at
> 0x7f17339e2580, file "<stdin>", line 2>)
>              12 LOAD_CONST               5 ('g.<locals>.f')
>              15 EXTENDED_ARG             3
>              18 MAKE_FUNCTION        196608
>              21 STORE_FAST               0 (f)
>              24 LOAD_CONST               0 (None)
>              27 RETURN_VALUE
>
> ... so I suppose people would want to run an AST pass instead?
> (and then evaluate the "annotations" parts of the AST by hand... uh)
>

Actually mypy uses an entirely different parser. This is mostly for
historical reasons: it started out as a compiler/checker/runtime for a
different, somewhat-Python-like statically-typed language. But I assume
that static checkers often have no choice in the matter and must write
their own parser -- e.g. PyCharm is itself written in Java and its parser
must work even if the code is not syntactically correct.

Another reason to use a different parser is that mypy needs to see the
comments so it can look for magic comments starting with "#type:". This is
typical for linters.

In general a type checker should not attempt to cope with clever things
(decorators or otherwise) that modify __annotations__; it should take the
expression tree of the annotation at face value. (It should of course know
about certain decorators like @property and other Python ideosyncracies
like self-passing for methods, and I think there should be a way to teach
it about new decorators. But executing Python code should not be part of
that.)


> >     Your proposal seems determined by the fact that mypy has much
> >     grander ambitions (and therefore requires its insertion into regular
> >     Python), but it doesn't make use of that power at all, worse, it
> >     forbids others to use it.
> >
> > This remark about mypy's ambitions sounds delusional and paranoid.
>
> It is entirely uncritical about mypy. It's fine to have other Python
> (or Python-like) implementations, even with deliberately different
> semantics. Such experimentations actually make the community much livelier
> than, say, PHP's or Ruby's.
>

OK, thanks for clarifying that. I took "grand ambitions" as a
(sarcastically) pejorative term, but you're right that it doesn't need to
be read like that.


> I don't know at which point mypy changed goals (if it has), but there are
> still signs in the website of the goal of building a separate runtime (not
> necessarily a separate syntax), e.g.
>
> """Also some language features that are evaluated at runtime in Python
> may happen during compilation in mypy when using the native semantics.
> For example, mypy base classes may be bound during compilation (or
> program loading, before evaluation), unlike Python."""
>

I have talked to Jukka about this, and he is definitely on board with
reducing mypy's functionality to that of a linter; I think there's even an
issue in mypy's tracker about removing the ability to execute the code
(currently there's a flag you must pass to prevent it from trying to run
the code). Updating the website is an ongoing low-priority project (you can
probably send him pull requests for it).


> Also the fact that mypy supports constructs such as "List[int]()". This
> is a set of design constraints that you're not bound to.
>

Yeah, I'm not crazy about that syntax (I think nobody is). It mostly exists
for the common use case where you have a function that is declared to
return e.g. a list of ints and you want to start off with an empty list;
the current mypy implementation complains about such code. Example:

def squares(xs: Sequence[float]) -> List[float]:
    sqs = []
    for x in xs:
        sqs.append(x**2)
    return sqs

mypy complains about the unannotated initialization of sqs. The two ways to
currently address this are

    sqs = []  # type: List[float]

or

    sqs = List[float]()

Neither is very attractive; mypy should just infer the type of sqs.

Nevertheless, I don't want to use call syntax to set parameters for generic
types, since a generic type still "feels" sufficiently like a class that
calling it is easily confused with instantiation -- even though ABCs are
typically not instantiable. (There's no hard rule for that though -- it is
merely the result of typical ABCs having at least one abstract method.)

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140825/9fdcc983/attachment.html>


More information about the Python-ideas mailing list