[Python-ideas] Delay evaluation of annotations
Steven D'Aprano
steve at pearwood.info
Thu Sep 22 23:06:16 EDT 2016
On Thu, Sep 22, 2016 at 07:21:18PM +0000, אלעזר wrote:
> On Thu, Sep 22, 2016 at 9:43 PM Steven D'Aprano <steve at pearwood.info> wrote:
>
> > On Thu, Sep 22, 2016 at 05:19:12PM +0000, אלעזר wrote:
> > > Hi all,
> > >
> > > Annotations of function parameters and variables are evaluated when
> > > encountered.
> >
> > Right, like all other Python expressions in general, and specifically
> > like function parameter default arguments.
> >
>
> Just because you call it "expression", when for most purposes it isn't - it
> is an annotation.
It is *both*. It's an expression, because it's not a statement or a
block. You cannot write:
def func(arg1: while flag: sleep(1), arg2: raise ValueError):
...
because the annotation must be a legal Python expression, not a code
block or a statement. It's an annotation because that's the
specific *purpose* of the expression in that context.
As an analogy: would you argue that it is wrong to call the for-loop
iterable an expression?
for <target-list> in <expression>:
block
I trust that you understand that the loop iterable can be any expression
that evaluates to an iterable. Well, annotations can be any expression
that evaluates to anything at all, but for the purposes of type
checking, are expected to evaluate to a string or a type object.
In the case of function annotations, remember that they can be any
legal Python expression. They're not even guaranteed to be type
annotations. Guido has expressed a strong preference that they are only
used as type annotations, but he hasn't yet banned other uses (and I
hope he doesn't), so any "solution" for a type annotation problem must
not break other uses.
> "Expression" is something that you need its value right
> now, and "annotation" is something that, well, annotates the code you see
> right now.
Right. In the case of Python, function annotations **do** have a runtime
effect: the expressions are evaluated, and the evaluated results are
assigned in function.__annotations__ and made available for runtime
introspection.
Don't think that function annotations are **only** for the static type
checker. Python is a much richer language than that!
> > > It is
> > > also easy to forget, and the result might be a (very uninteresting)
> > > exception in certain untested paths, e.g. inside functions.
> >
> > Unlikely, unless you're talking about functions nested inside other
> > functions, or unusual (but legal and sometimes useful) conditional
> > definitions:
>
> I was thinking about the former, but yeah, uncovered code will fail at
> runtime, possibly in production, for *no* real reason. I do not claim that
> this is common, but it is definitely unnecessary - unlike initialization
> expressions.
Unnecessary?
class MyClass:
pass
def function(arg: MyCalss):
...
I want to see an immediate NameError here, thank you very much, even if
I'm not running a static checker. I don't want to have to manually call:
function.__annotations__['arg']()
to see whether or not the annotation is valid.
I accept that using strings as forward annotations is not a foolproof
solution either:
def function(arg: 'MyCalss'):
...
but let's not jump into a "fix" that actually makes things worse.
> > if condition:
> > # forward reference to MyClass
> > def f(arg:'MyClass'): ...
> > else:
> > # oops, untested path
> > def f(arg:MyClass): ...
> >
> > class MyClass: ...
> >
> >
> > But generally speaking, that sort of code is unusual, and besides, if
> > you're doing this, either the static type checker won't be able to cope
> > with it at all (in which case there's little point in annotating the
> > function), or it will cope, and detect the invalid annotation.
> >
> Why would it detect invalid annotation here? It shouldn't.
MyClass doesn't exist at that point, so it is in invalid annotation.
> > > help editors in syntax highlighting and name lookup.
> >
> > But will harm runtime introspection.
> >
>
> Very little. And to quote Frank Miller, “An old man dies, a little girl
> lives. Fair trade.”
Not to the old man, and especially not if the little girl is a
psychopath who grows up to become a mass murdering totalitarian
dictator.
--
Steve
More information about the Python-ideas
mailing list