[Python-3000] Adaptation and type declarations

Guido van Rossum guido at python.org
Mon Apr 10 23:57:09 CEST 2006


[Guido]
> > It should mean neither. As I tried to say, the *only*
> > semantics is that the value of the expression is
> > accessible through the __signature__ attribute of
> > the function. It is then up to the decorator to decide
> > what it means.

[Jim Jewett]
> So type annotation is only for use with decorators, not for general
> documentation or compiler speedups?

Those are two entirely different purposes. It's fine for
documentation, for use by IDEs, and for use by e.g. pychecker.
However, using it for compiler speedups is unlikely given the run-time
semantics and Python's extremely dynamic nature.

> > > If adaptation is light enough to be useful, then I
> > > can't see any reason to prefer the first.
>
> > >     def f(a:0<a<10): ...
>
> > > isn't *that* much cleaner than whichever of
>
> > >     def f(a:clip_to_int_range(0,10)): ...
> > >     def f(a:int_in_range(0,10)): ...
> > >     def f(a:clip_to_number_range(0,10)): ...
> > >     def f(a:number_in_range(0,10)): ...
>
> > > was actually intended.

Oops. I guess you were arguing *against* the former; I (and perhaps
others) misread your mail as arguing *for* the "a:0<a<10" form, which
isn't so strange since nobody proposed that before (unless I missed
it).

> > That's not something I had considered. It would have to
> > turn the expression into an implicit lambda (or an AST),
> > which isn't something we should do lightly, and which
> > conflicts with other proposed uses, where the value of
> > the expression is made available to the decorator
> > -- the value of '0<a<10' is not available until f is *called*.
>
> I suppose I should have supplied definitions, just to be explicit.  For example:
>
>     def number_in_range(min, max):
>         def checker(val):
>             if min < val < max:
>                 return val
>             raise ValueError("%s not between %s and %s",
>                              (val, min, max))
>         return checker
>
> Then checker (the actual predicate) is available at compile time; the
> only thing waiting for run time is the result of checker(a) for that
> particular call.

This is perfectly reasonable.

> Or were you just saying that even the predicate-only simple expression
> version should really have been written as
>
>     def f(a:lambda a:(0<a<10)): ...
>
> so that there would be a complete predicate available independent of
> the function itself?

I'm still confused; I'm tempted to say "yes of course" because
'0<a<10' when evaluated at function definition time will raise a
NameError (or worse, use a global variable named 'a'). My confusion is
why you would bring this up only to shoot it down.

> If so, then I can't see any reason not to require that the type
> markers be callables whose return value is used in place of the
> argument.

Again a double negative, possibly confusing me.

And again, I don't want to assign *any* semantics to the type markers;
requiring them to be "adaptation" functions vastly reduces their
usefulness IMO. E.g. I'd like to be able to have a decorator that
requires the convention of using concrete types (e.g. list, int, file)
as type markers; calling these would be a mistake, they should be used
in isinstance() calls for example.

> There is nothing to prevent the type markers from returning the
> original object (possibly with extra annotations).

There is if you want to use existing concrete types. list(x) is
defined as returning a new list. Etc.

> For efficiency,
> that should be the normal case.  Nor is there anything preventing a
> decorator (if you assume there will always be one) from changing the
> signature anyhow.  The only downside is an additional call per
> annotated argument *if* neither the decorator nor the compiler has
> used the information to optimize something away.

You're thinking of the type markers as adapters exclusively. I'm
trying to promote the idea that they could be anything and that they
are only constrained by the implicit contract of the decorator used
(if any).

That's what "used for documentation purposes only" means. Several
people (in a previous round of discussion) have agreed that they'd be
totally happy if

def f(x: int):
    print x*2
f("abc")

executed as if the ": int" part was not present (hence printing "abcabc").

--
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list