[Python-Dev] PEP 484 update proposal: annotating decorated declarations

Jukka Lehtosalo jlehtosalo at gmail.com
Wed May 10 08:23:05 EDT 2017


Even if Callable types will soon support keyword arguments, the syntax for
Callables will look quite different from function definitions and this
inconsistency may hurt readability, at least for more complex signatures.
We could work around this by using the def syntax for the declared type of
a decorator. For example:

@declared_type
def session(url: str) -> ContextManager[DatabaseSession]: ...  # Explicit
'...'

@contextmanager
def session(url: str) -> Iterator[DatabaseSession]:
    s = DatabaseSession(url)
    ...

This would be quite similar to how overloads work, so there is a precedent
for something like this. We could require or recommend that the declared
type comes immediately before the implementation so that the entire
definition of a single function would not be too spread out.

This won't help if the decorated type is not a callable. We could support
this use case by using the normal variable annotation syntax:

thing: Decorated  # Declared type of 'thing'

@decorator
def thing() -> int:
    ...

Jukka

On Wed, May 10, 2017 at 12:27 AM, Naomi Seyfer <naomi at seyfer.org> wrote:

> Stay tuned for the pep that allows callable to take keyword args.
>
> On May 9, 2017, at 3:59 PM, Brett Cannon <brett at python.org> wrote:
>
> The idea seems reasonable to me when viewing type hints as a form of
> documentation as it helps remind people how they are expected to call the
> final function.
>
> One worry I do have, though, is Callable doesn't support keyword-only
> parameters, so declared_type won't work in all cases without Callable
> gaining such support (for those that don't know, Callable didn't start with
> that support as Callable has been meant for callback scenarios up to this
> point).
>
> On Tue, 9 May 2017 at 10:21 Guido van Rossum <guido at python.org> wrote:
>
>> There's a PR to the peps proposal here:
>> https://github.com/python/peps/pull/242
>>
>> The full text of the current proposal is below. The motivation for this
>> is that for complex decorators, even if the type checker can figure out
>> what's going on (by taking the signature of the decorator into account),
>> it's sometimes helpful to the human reader of the code to be reminded of
>> the type after applying the decorators (or a stack thereof). Much
>> discussion can be found in the PR. Note that we ended up having `Callable`
>> in the type because there's no rule that says a decorator returns a
>> function type (e.g. `property` doesn't).
>>
>> This is a small thing but I'd like to run it by a larger audience than
>> the core mypy devs who have commented so far. There was a brief discussion
>> on python-ideas (my original
>> <https://mail.python.org/pipermail/python-ideas/2017-April/045548.html>,
>> favorable reply
>> <https://mail.python.org/pipermail/python-ideas/2017-May/045550.html> by
>> Nick, my response
>> <https://mail.python.org/pipermail/python-ideas/2017-May/045557.html>).
>>
>> Credit for the proposal goes to Naomi Seyfer, with discussion by Ivan
>> Levkivskyi and Jukka Lehtosalo.
>>
>> If there's no further debate here I'll merge it into the PEP and an
>> implementation will hopefully appear in the next version of the typing
>> module (also hopefully to be included in CPython 3.6.2 and 3.5.4).
>>
>> Here's the proposed text (wordsmithing suggestions in the PR please):
>>
>> +Decorators
>> +----------
>> +
>> +Decorators can modify the types of the functions or classes they
>> +decorate. Use the ``decorated_type`` decorator to declare the type of
>> +the resulting item after all other decorators have been applied::
>> +
>> + from typing import ContextManager, Iterator, decorated_type
>> + from contextlib import contextmanager
>> +
>> + class DatabaseSession: ...
>> +
>> + @decorated_type(Callable[[str], ContextManager[DatabaseSession]])
>> + @contextmanager
>> + def session(url: str) -> Iterator[DatabaseSession]:
>> + s = DatabaseSession(url)
>> + try:
>> + yield s
>> + finally:
>> + s.close()
>> +
>> +The argument of ``decorated_type`` is a type annotation on the name
>> +being declared (``session``, in the example above). If you have
>> +multiple decorators, ``decorated_type`` must be topmost. The
>> +``decorated_type`` decorator is invalid on a function declaration that
>> +is also decorated with ``overload``, but you can annotate the
>> +implementation of the overload series with ``decorated_type``.
>> +
>>
>> --
>> --Guido van Rossum (python.org/~guido <http://python.org/%7Eguido>)
>> _______________________________________________
>> Python-Dev mailing list
>> Python-Dev at python.org
>> https://mail.python.org/mailman/listinfo/python-dev
>> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
>> brett%40python.org
>>
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> jlehtosalo%40gmail.com
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20170510/abcf2b19/attachment-0001.html>


More information about the Python-Dev mailing list