[Python-Dev] PEP 484 update proposal: annotating decorated declarations
Guido van Rossum
guido at python.org
Tue May 30 17:02:02 EDT 2017
> On 15 May 2017 at 10:48, Koos Zevenhoven <k7hoven at gmail.com> wrote:
>
>> Would __annotations__ be set by the decorator? To me, not setting them
>> would seem weird, but cases where the result is not a function could
>> be weird. I also don't see a mention of this only working in stubs.
>>
>
It took me a while to realize which annotations we're talking about here.
I like Jukka's version, as it has a clear distinction between
>> functions and other attributes. But that might require a language
>> change to provide __annotations__ in a clean manner? Maybe that
>> language change would be useful elsewhere.
>
>
I'm not interesting in language changes to solve this problem.
On Mon, May 15, 2017 at 6:20 AM, Ivan Levkivskyi <levkivskyi at gmail.com>
wrote:
> With original syntax it is possible to overwrite annotations without
> language changes.
> However with Jukka's syntax it looks difficult. A possible pure-Python way
> could be
> to insert an item in an enclosing __annotations__, if an enclosing scope
> is a class or module scope.
>
I assume we're talking about `session.__annotations__`, which will be
overwritten by the last definition (i.e. the "implementation"). This is
only a runtime problem, and we're actually still a bit better off here than
for @overload -- for @overload, the implementation is often un-annotated or
has very vague annotations (e.g. `*args: Any`), while here the annotations
are in principle preserved by the decorators on the implementation
function. (The main premise of the proposal under discussion is to clarify
the type for the *human* reader, although in some edge cases the explicit
annotation may provide a constraint for the naturally inferred type of the
decorated function.)
But in either case the annotations on the overload variants or the
"declaration" are lost at runtime by the trick of using multiple
definitions, since at runtime the last definition wins. (And we don't want
to go through the contortions used by e.g. @property for collecting getters
and setters belonging to a single attribute.)
The question then is, do we care more about the runtime accessibility of
the type, or do we care more about ease of use in a context of static
analysis? In general with the design of PEP 484 I've tried to balance the
two (and several other constraints like no changes to the core Python
language).
I'm still not decided. Let's compare the two proposals quickly. In Naomi's
version you'd write
@decorated_type(Callable[[str], ContextManager[DbSession]])
@contextmanager
def session(url: str) -> Iterator[DbSession]:
<body>
while in Jukka's version you'd write
@declared_type
def session(url: str) -> ContextManager[DbSession]: ...
@contextmanager
def session(url: str) -> Iterator[DbSession]:
<body>
There's also a difference in power between the two: in Naomi's proposal,
session's type becomes exactly
Callable[[str], ContextManager[DbSession]]
which can only be called with positional arguments, whereas in Jukka's
proposal session will retain the name and clasiffication (e.g.
keyword-only, varargs) of the arguments. If those are important, in Naomi's
case this can be written using the new "argspecs" form of Callable, i.e.
@decorated_type(Callable[[Arg(str, 'url')], ContextManager[DbSession])
@contextmanager
def session <etc.>
which is definitely more verbose and uglier than Jukka's version. OTOH it
does mean that Naomi's proposal has all the *power* of Jukka's version --
and in simple cases it is actually less verbose than Jukka's proposal (in
cases where you want all that power -- if you're happy with a basic
callable it's actually *less* verbose).
Jukka's version also needs another special case where the decorator returns
something that's not a callable. In Naomi's proposal this would simply be
@decorated_type(SomeType)
@some_decorator
def my_thing(url: str) -> int:
<etc.>
Jukka's proposal *seems* to be to just allow overriding a variable
declaration with a function declararion:
my_thing: SomeType
@some_decorator
def my_thing <etc.>
This seems fragile to me (since it looks like an accidental redefinition,
although typically the static check would find a discrepancy between the
inferred type of the first and the second definition).
All in all I'm still leaning towards Naomi's original proposal -- it looks
simpler to implement as well.
--
--Guido van Rossum (python.org/~guido <http://python.org/%7Eguido>)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20170530/a3c73c54/attachment.html>
More information about the Python-Dev
mailing list