Ken Jin <kenjin4...@gmail.com> added the comment:

@larry
> Is this "surprising, but required" behavior due specifically to this being a 
> backwards-incompatible change?

Yes. That's the main factor. I've since learnt that there's sadly more to it 
though :( (see below).

> Does that mean I don't have the problem you're solving by reversing the order 
> of namespace lookup, and I can just pass globals and locals in like normal?

I think it depends on the ergonomics of the function you're trying to achieve. 
I admit I haven't been fully keeping up with the inspect.get_annotations issue 
(sorry!), but here's what I learnt from get_type_hints:

(Partly copied over from PR 25632)
Example:

from typing import TypeVar, Generic
T = TypeVar('T')

class A(Generic[T]):
    __annotations__ = dict(
        some_b='B'
    )


class B(Generic[T]):
    class A(Generic[T]):
        pass
    __annotations__ = dict(
        my_inner_a1='B.A',
        my_inner_a2=A,
        my_outer_a='A'  # unless somebody calls get_type_hints with 
localns=B.__dict__
    )

>>> get_type_hints(B)

Currently (globalns then localns):
{'my_inner_a1': <class '__main__.B.A'>, 'my_inner_a2': <class '__main__.B.A'>, 
'my_outer_a': <class '__main__.A'>}

Swapped (localns then globalns):
{'my_inner_a1': <class '__main__.B.A'>, 'my_inner_a2': <class '__main__.B.A'>, 
'my_outer_a': <class '__main__.B.A'>}

I realized that looking into globalns then localns is a necessary evil: doing 
the converse (looking into localns first then globalns) would mean there is no 
way to point to the shadowed global `A`: it would always point to the local 
`B.A`. Unless of course you pass in localns=module.__dict__ or 
localns=globals().

Ultimately I think it's a sacrifice of ergonomics either way; looking into 
localns then globalns will require passing in the module's __dict__ to refer to 
a global being shadowed, while the converse (globalns then localns) introduces 
surprising eval behavior. Both are kind of tacky, but globalns then localns is 
slightly less so IMO. If the user wants to specify the inner class, they can 
just annotate 'B.A', if they want the outer, it's 'A'. But the localns then 
globalns approach will always point to `B.A`, the only way to access the 
shadowed global `A` is to pass in the strange looking argument 
localns=module.__dict__.

Phew, my head's spinning with localns and globalns now. Thanks for reading! I 
think it's your call. I'm inexperienced with elegant function design :P.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue42904>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to