PEP 563 also requires using ``eval()`` or ``typing.get_type_hints()``to examine annotations. Code updated to work with PEP 563 that calls``eval()`` directly would have to be updated simply to remove the``eval()`` call. Code using ``typing.get_type_hints()`` wouldcontinue to work unchanged, though future use of that functionwould become optional in most cases.
I think it is worth noting somewhere that string annotations are still valid, and should still be evaluated if so.
That's not up to me, it's up to the static type checkers who
created that idiom. But I assume they'll continue to support
stringized annotations, whether manually or automatically created.
Because this PEP makes semantic changes to how annotations areevaluated, this PEP will be initially gated with a per-module``from __future__ import co_annotations`` before it eventuallybecomes the default behavior.
Is it safe to assume that a module that does not import co_annotations, but imports a module that does, will exhibit PEP 649 behavior when the former accesses an annotation defined in the latter?
* *Code that sets annotations on module or class attributesfrom inside any kind of flow control statement.* It'scurrently possible to set module and class attributes withannotations inside an ``if`` or ``try`` statement, and it worksas one would expect. It's untenable to support this behaviorwhen this PEP is active.
Is the following an example of the above?
@dataclassclass Foo:if some_condition:x: intelse:x: floatIf so, would the following still be valid?
if some_condition:type_ = intelse:type_ = float@dataclassclass Foo:x: type_
Your example was valid, and I think your workaround should be
fine. Do you have a use case for this, or is this question
motivated purely by curiosity?
It's fine to modify the __annotations__ dict after the creation of the class or module. It's code that modifies "__annotations__" from within the class or module that is disallowed here. Similarly for dataclasses; once it creates a class object, it can explicitly set and / or modify the annotations dict on that class.* *Code in module or class scope that references or modifies thelocal* ``__annotations__`` *dict directly.* Currently, whensetting annotations on module or class attributes, the generatedcode simply creates a local ``__annotations__`` dict, then setsmappings in it as needed. It's also possible for user codeto directly modify this dict, though this doesn't seem like it'san intentional feature. Although it would be possible to supportthis after a fashion when this PEP was active, the semanticswould likely be surprising and wouldn't make anyone happy.
I recognize the point you make later about its impact on static type checkers. Setting that aside, I'm wondering about caes where annotations can be dynamically generated, such as dataclasses.make_dataclass(...). And, I could see reasons for overwriting values in __annotations__, especially in the case where it may be stored as a string and one wants to later affix its evaluated value. These are considerations specific to runtime (dynamic) type checking.
I wonder if it would make sense for each item in __annotations__ to be evaluated separately on first access of each key, rather than all __annotations__ on first access to the dict. Basically the dict would act as a LazyDict. It could also provide the benefit of lessening the expense of evaluating complex but otherwise unused annotations.
This would cause an immense proliferation of code objects (with some pre-bound to function objects). Rather than one code object per annotation dict, it would create one code object per annotation key. Also, we don't have a "lazy dict" object built in to Python, so we'd have to create one.
I don't have any problems that this would solve, so I'm not super
interested in it. Personally I'd want to see a real compelling
use case for this feature before I'd consider adding it to
Python. Of course, I'm not on the steering committee, so my
opinion is only worth so much.