On Sep 13, 2017, at 9:44 PM, Nick Coghlan
wrote: On 14 September 2017 at 09:43, Lukasz Langa
wrote: On Sep 13, 2017, at 6:37 PM, Nick Coghlan
wrote: That way, during the "from __future__ import lazy_annotations" period, folks will have clearer guidance on how to explicitly opt-in to eager evaluation via function and class decorators. I like this idea! For classes it would have to be a function that you call post factum. The way class decorators are implemented, they cannot evaluate annotations that contain forward references. For example:
class Tree: left: Tree right: Tree
def __init__(self, left: Tree, right: Tree): self.left = left self.right = right
This is true today, get_type_hints() called from within a class decorator will fail on this class. However, a function performing postponed evaluation can do this without issue. If a class decorator knew what name a class is about to get, that would help. But that's a different PEP and I'm not writing that one ;-)
The class decorator case is indeed a bit more complicated, but there are a few tricks available to create a forward-reference friendly evaluation environment.
Using cls.__name__ and the ChainMap is clever, I like it. It might prove useful for Eric's data classes later. However, there's more to forward references than self-references: class A: b: B class B: ... In this scenario evaluation of A's annotations has to happen after the module is fully loaded. This is the general case. No magic decorator will solve this. The general solution is running eval() later, when the namespace is fully populated. I do agree with you that a default implementation of a typing-agnostic variant of `get_type_hints()` would be nice. If anything, implementing this might better surface limitations of postponed annotations. That function won't be recursive though as your example. And I'll leave converting the function to a decorator as an exercise for the reader, especially given the forward referencing caveats. - Ł