
On Mon, Jan 11, 2021 at 1:20 PM Larry Hastings <larry@hastings.org> wrote:
PEP 563 states:
For code that uses type hints, the typing.get_type_hints(obj, globalns=None, localns=None) function correctly evaluates expressions back from its string form.
So, if you are passing in a localns argument that isn't None, okay, but you're not using them "correctly" according to the language. Also, this usage won't be compatible with static type checkers.
I think you're misreading PEP 563 here. The mention of globalns=None, localns=None refers to the fact that these parameters have defaults, not that you must pass None. Note that the next paragraph in that PEP mentions eval(ann, globals, locals) -- it doesn't say eval(ann, {}, {}). There is considerable discussion below in that same section, but it doesn't come closer than stating "using local state in annotations is no longer possible in general", and it states that get_type_hints() correctly provides the right localns for classes. Apart from how PEP 563 should be interpreted (maybe we should ask Lukasz) I would say that basically all feedback I've seen over the changed semantics of annotations in 3.10 is about this problem, and when I first saw your proposal I thought that this would solve those issues. I'd be much less enthusiastic if we're still going to force annotations to only reference globals. My read on PEP 563 is that it *primarily* solves the issue of having to put forward references in string quotes (the most common case probably being methods that accept or return an instance of the class in which they are being defined). You have come up with a better solution for that -- the solution that eluded us all when we were debating PEP 563. But I think that you should try for maximal backward compatibility with the state of the world *before* PEP 563. In particular, static type checkers have no problem with annotations referencing types defined in the local scope. This has always worked (hence the complaints about PEP 563) and it would actually be extra work to forbid this in certain situations but not others. [...]
*2. __co_annotations__ scope?*
I'm wondering why __co_annotations__ function could not be scoped (within a closure?) such that it can access the values where the function, method, class or module are being declared? I acknowledge that I'm railing against PEP 563 again, trying to reclaim lost ground.
This is addressed in PEP 563, when it rejected the idea of using "function local state when defining annotations":
This would be prohibitively expensive for highly annotated code as the frames would keep all their objects alive. That includes predominantly objects that won't ever be accessed again.
https://www.python.org/dev/peps/pep-0563/#keeping-the-ability-to-use-functio...
But that's a strawman for your PEP. In PEP 563, they would have to keep the whole frame alive. But with your PEP only the cells containing objects that are *actually* referenced by annotations, i.e. exactly the objects that the user wants to see preserved in `__annotations__`. (Well, at Instagram they probably don't want to see any annotations survive the compilation stage, but they can hack their own Python compiler -- we know they do that anyway. :-) Later in that same section, PEP 563 points out a problem with annotations that reference class-scoped variables, and claims that the implementation would run into problems because methods can't "see" the class scope. This is indeed a problem for PEP 563, but *you* can easily generate correct code, assuming the containing class exists in the global scope (and your solution requires that anyway). So in this case ``` class Outer: class Inner: ... def method(self, a: Inner, b: Outer) -> None: ... ``` The generated code for the `__annotations__` property could just have a reference to `Outer.Inner` for such cases: ``` def __annotations__(): return {"a": Outer.Inner, "b": Outer, "return": None} ``` (Note that for *function* locals you don't have to do anything, they just work, because of closures -- you may not understand them, but they are important here. :-) -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>