With PEP 563 behavior going mainstream in Python 3.10, I see some
ramifications, especially for runtime validation of type hints:

1. PEP 563 is changing the scope of evaluation of type hints, and in
some cases it is not feasible to move that scope to the annotated
object's globals. (I appreciate the reality that such cases would evade
static type checkers.)

2. The typing.get_type_hints function causes annotation(s) to be
evaluated from strings for every call, incurring a potentially
significant runtime penalty depending on how often type hints are
evaluated at runtime.

To address both of these issues, I'm proposing that a new function be
added to typing: affix_type_hints.

I'm thinking something like this:


def affix_type_hints(obj, globalns=None, localns=None):
    """
    Affixes an object's type hints to the object.

    Type hints are affixed by first being resolved through
    get_type_hints, then by storing the result in the object's
    __annotations__ attribute.

    If the object is a class, this function will affix annotations from all
    superclasses.
    """

    if hints := typing.get_type_hints(obj, globalns, localns, 
include_extras=True):
        obj.__annotations__ = hints


Advantages:

1. The time and scope of type hint affixation are under the control of
the caller. Future references can be realized before type hints are
affixed. If there is a novel local scope required to resolve the type
hint, it can be supplied in-context; future calls to get_type_hints
inherit the benefit of such pre-resolution.

2.  Annotations will not be re-evaluated on repeated calls to
get_type_hints.

3. It doesn't require a change to the behavior of the get_type_hints
function.


Disadvantages:

1. Subclasses inheriting superclass annotations may be undesirable.

2. Monkey-patching __annotations__ may be considered an anti-pattern. 

3. Maybe allowing re-evaluation on every get_type_hints call is
desirable? (I'd rather avoid the potential for side-effects.)

4. The cited example is a 2-line function; perhaps its triviality makes
it unjustified to add to the stdlib.


Alternatives:

1. A caching version of get_type_hints. It looks like
ForwardRef.__forward_value__ could actually deliver if annotations were
encoded as ForwardRef objects instead of string literals. Am I missing
a way for ForwardRef to cache evaluated values when get_type_hints is
called?

2. Something I haven't considered? Please let me know.


Paul
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/GZ7QGEABF624C6SKHUG7CWQAJ3XTJLIO/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to