Hi Zachary,
Some much-belated thoughts:
I think the most basic reason this doesn’t really work as a replacement for PEP 563/649 is that it misses one of their key motivations, which is to reduce/eliminate the import-time and memory overhead of annotations in large codebases that are heavily annotated but don’t introspect most of the annotations at runtime. This cost can be very significant, especially with more complex annotations that aren’t just a single name, but have to resolve a series of subscriptings etc.
I still think the idea is interesting as something that could compose with PEP 649. Specifically, it looks like the upcoming updated draft of 649 will include an enhanced ForwardRef
that is pretty similar in concept to your DefRef
. If someone asks to introspect PEP 649 annotations in a lenient “hybrid” mode, nonexistent names will implicitly be replaced by ForwardRef
objects. I think it’s good to have this option available so that e.g. cyclic dataclasses can work out of the box with minimal boilerplate. But if you are writing a library that introspects annotations, there’s no reason you can’t choose to introspect annotations in the default mode (where all names must exist), and ask your users to instead explicitly create ForwardRef
objects in advance as needed (including possibly by using a context manager like defer_imports()
instead of putting imports under if TYPE_CHECKING:
). This approach can coexist nicely in the same ecosystem, since in the end the ForwardRef
objects will look and behave the same, whether created explicitly and manually or implicitly via hybrid-mode introspection.
I think there might need to be a clearer demonstration of widespread interest in this explicit approach (perhaps by adoption of a third-party library, since AFAICT everything you’ve suggested is doable as a third-party library) before it would make sense to include this in the standard library.